public async Task <BuildResult> CallAsync() { IReadOnlyList <BlobDescriptor> baseImageDescriptors = await pushBaseImageLayersStep.GetFuture().ConfigureAwait(false); IReadOnlyList <BlobDescriptor> appLayerDescriptors = await pushApplicationLayersStep.GetFuture().ConfigureAwait(false); BlobDescriptor containerConfigurationBlobDescriptor = await pushContainerConfigurationStep.GetFuture().ConfigureAwait(false); ImmutableHashSet <string> targetImageTags = buildConfiguration.GetAllTargetImageTags(); using (var progressEventDispatcher = progressEventDispatcherFactory.Create("pushing image manifest", this.Index)) using (var factory = progressEventDispatcher.NewChildProducer()("[child progress]pushing image manifest", targetImageTags.Count)) using (TimerEventDispatcher ignored = new TimerEventDispatcher(buildConfiguration.GetEventHandlers(), DESCRIPTION)) { RegistryClient registryClient = buildConfiguration .NewTargetImageRegistryClientFactory() .SetAuthorization(await authenticatePushStep.GetFuture().ConfigureAwait(false)) .NewRegistryClient(); // Constructs the image. ImageToJsonTranslator imageToJsonTranslator = new ImageToJsonTranslator(await buildImageStep.GetFuture().ConfigureAwait(false)); // Gets the image manifest to push. IBuildableManifestTemplate manifestTemplate = imageToJsonTranslator.GetManifestTemplate( buildConfiguration.GetTargetFormat(), containerConfigurationBlobDescriptor); // Pushes to all target image tags. IList <Task <DescriptorDigest> > pushAllTagsFutures = new List <Task <DescriptorDigest> >(); var idx = 0; ProgressEventDispatcher.Factory progressEventDispatcherFactory = factory.NewChildProducer(); foreach (string tag in targetImageTags) { idx++; using (progressEventDispatcherFactory.Create("tagging with " + tag, idx)) { buildConfiguration.GetEventHandlers().Dispatch(LogEvent.Info("Tagging with " + tag + "...")); pushAllTagsFutures.Add(registryClient.PushManifestAsync(manifestTemplate, tag)); } } DescriptorDigest imageDigest = await Digests.ComputeJsonDigestAsync(manifestTemplate).ConfigureAwait(false); DescriptorDigest imageId = containerConfigurationBlobDescriptor.GetDigest(); BuildResult result = new BuildResult(imageDigest, imageId); await Task.WhenAll(pushAllTagsFutures).ConfigureAwait(false); return(result); } }
/** * Saves a manifest and container configuration for a V2.2 or OCI image. * * @param imageReference the image reference to save the manifest and container configuration for * @param manifestTemplate the V2.2 or OCI manifest * @param containerConfigurationTemplate the container configuration * @throws IOException if an I/O exception occurs */ public async Task WriteMetadataAsync( IImageReference imageReference, IBuildableManifestTemplate manifestTemplate, ContainerConfigurationTemplate containerConfigurationTemplate) { await cacheStorageWriter.WriteMetadataAsync( imageReference, manifestTemplate, containerConfigurationTemplate).ConfigureAwait(false); }
/** * Pushes the image manifest for a specific tag. * * @param manifestTemplate the image manifest * @param imageTag the tag to push on * @return the digest of the pushed image * @throws IOException if communicating with the endpoint fails * @throws RegistryException if communicating with the endpoint fails */ public async Task <DescriptorDigest> PushManifestAsync(IBuildableManifestTemplate manifestTemplate, string imageTag) { ManifestPusher pusher = new ManifestPusher(registryEndpointRequestProperties, manifestTemplate, imageTag, eventHandlers); DescriptorDigest descriptorDigest = await CallRegistryEndpointAsync(pusher).ConfigureAwait(false); Debug.Assert(descriptorDigest != null); return(descriptorDigest); }
public ManifestPusher( RegistryEndpointRequestProperties registryEndpointRequestProperties, IBuildableManifestTemplate manifestTemplate, string imageTag, IEventHandlers eventHandlers) { this.registryEndpointRequestProperties = registryEndpointRequestProperties; this.manifestTemplate = manifestTemplate; this.imageTag = imageTag; this.eventHandlers = eventHandlers; }
/** Tests translation of image to {@link BuildableManifestTemplate}. */ private async Task TestGetManifestAsync( ManifestFormat manifestTemplateClass, string translatedJsonFilename) { // Loads the expected JSON string. SystemPath jsonFile = Paths.Get(TestResources.GetResource(translatedJsonFilename).ToURI()); string expectedJson = Encoding.UTF8.GetString(Files.ReadAllBytes(jsonFile)); // Translates the image to the manifest and writes the JSON string. ContainerConfigurationTemplate containerConfiguration = imageToJsonTranslator.GetContainerConfiguration(); BlobDescriptor blobDescriptor = await Digests.ComputeJsonDescriptorAsync(containerConfiguration).ConfigureAwait(false); IBuildableManifestTemplate manifestTemplate = imageToJsonTranslator.GetManifestTemplate(manifestTemplateClass, blobDescriptor); Assert.AreEqual(expectedJson, JsonTemplateMapper.ToUtf8String(manifestTemplate)); }
/** * Gets a {@link BuildResult} from an {@link Image}. * * @param image the image * @param targetFormat the target format of the image * @return a new {@link BuildResult} with the image's digest and id * @throws IOException if writing the digest or container configuration fails */ public static async Task <BuildResult> FromImageAsync(Image image, ManifestFormat targetFormat) { ImageToJsonTranslator imageToJsonTranslator = new ImageToJsonTranslator(image); ContainerConfigurationTemplate configurationTemplate = imageToJsonTranslator.GetContainerConfiguration(); BlobDescriptor containerConfigurationBlobDescriptor = await Digests.ComputeJsonDescriptorAsync(configurationTemplate).ConfigureAwait(false); IBuildableManifestTemplate manifestTemplate = imageToJsonTranslator.GetManifestTemplate( targetFormat, containerConfigurationBlobDescriptor); DescriptorDigest imageDigest = await Digests.ComputeJsonDigestAsync(manifestTemplate).ConfigureAwait(false); DescriptorDigest imageId = containerConfigurationBlobDescriptor.GetDigest(); return(new BuildResult(imageDigest, imageId)); }
/** * Gets the manifest as a JSON template. The {@code containerConfigurationBlobDescriptor} must be * the {@link BlobDescriptor} obtained by writing out the container configuration JSON returned * from {@link #getContainerConfiguration()}. * * @param <T> child type of {@link BuildableManifestTemplate}. * @param manifestTemplateClass the JSON template to translate the image to. * @param containerConfigurationBlobDescriptor the container configuration descriptor. * @return the image contents serialized as JSON. */ public IBuildableManifestTemplate GetManifestTemplate( ManifestFormat manifestFormat, BlobDescriptor containerConfigurationBlobDescriptor) { containerConfigurationBlobDescriptor = containerConfigurationBlobDescriptor ?? throw new ArgumentNullException(nameof(containerConfigurationBlobDescriptor)); try { IBuildableManifestTemplate template; // ISet up the JSON template. switch (manifestFormat) { case ManifestFormat.V22: template = new V22ManifestTemplate(); break; case ManifestFormat.OCI: template = new OCIManifestTemplate(); break; default: throw new ArgumentOutOfRangeException(nameof(manifestFormat)); } IBuildableManifestTemplate buildableTemplate = template; // Adds the container configuration reference. DescriptorDigest containerConfigurationDigest = containerConfigurationBlobDescriptor.GetDigest(); long containerConfigurationSize = containerConfigurationBlobDescriptor.GetSize(); buildableTemplate.SetContainerConfiguration(containerConfigurationSize, containerConfigurationDigest); // Adds the layers. foreach (ILayer layer in image.GetLayers()) { buildableTemplate.AddLayer( layer.GetBlobDescriptor().GetSize(), layer.GetBlobDescriptor().GetDigest()); } // Serializes into JSON. return(template); } catch (JsonException ex) { throw new ArgumentException(manifestFormat + " cannot be instantiated", ex); } }
/** * Saves the manifest and container configuration for a V2.2 or OCI image. * * @param imageReference the image reference to store the metadata for * @param manifestTemplate the manifest * @param containerConfiguration the container configuration */ public async Task WriteMetadataAsync( IImageReference imageReference, IBuildableManifestTemplate manifestTemplate, ContainerConfigurationTemplate containerConfiguration) { manifestTemplate = manifestTemplate ?? throw new ArgumentNullException(nameof(manifestTemplate)); Preconditions.CheckNotNull(manifestTemplate.GetContainerConfiguration()); Preconditions.CheckNotNull(manifestTemplate.GetContainerConfiguration().Digest); SystemPath imageDirectory = cacheStorageFiles.GetImageDirectory(imageReference); Files.CreateDirectories(imageDirectory); using (LockFile ignored1 = LockFile.Create(imageDirectory.Resolve("lock"))) { await WriteMetadataAsync(manifestTemplate, imageDirectory.Resolve("manifest.json")).ConfigureAwait(false); await WriteMetadataAsync(containerConfiguration, imageDirectory.Resolve("config.json")).ConfigureAwait(false); } }
public async Task TestWriteMetadata_v22Async() { SystemPath containerConfigurationJsonFile = Paths.Get( TestResources.GetResource("core/json/containerconfig.json").ToURI()); ContainerConfigurationTemplate containerConfigurationTemplate = JsonTemplateMapper.ReadJsonFromFile <ContainerConfigurationTemplate>( containerConfigurationJsonFile); SystemPath manifestJsonFile = Paths.Get(TestResources.GetResource("core/json/v22manifest.json").ToURI()); IBuildableManifestTemplate manifestTemplate = JsonTemplateMapper.ReadJsonFromFile <V22ManifestTemplate>(manifestJsonFile); ImageReference imageReference = ImageReference.Parse("image.reference/project/thing:tag"); await new CacheStorageWriter(cacheStorageFiles) .WriteMetadataAsync(imageReference, manifestTemplate, containerConfigurationTemplate).ConfigureAwait(false); SystemPath savedManifestPath = cacheRoot.Resolve("images/image.reference/project/thing!tag/manifest.json"); SystemPath savedConfigPath = cacheRoot.Resolve("images/image.reference/project/thing!tag/config.json"); Assert.IsTrue(Files.Exists(savedManifestPath)); Assert.IsTrue(Files.Exists(savedConfigPath)); V22ManifestTemplate savedManifest = JsonTemplateMapper.ReadJsonFromFile <V22ManifestTemplate>(savedManifestPath); Assert.AreEqual( "8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad", savedManifest.GetContainerConfiguration().Digest.GetHash()); ContainerConfigurationTemplate savedContainerConfig = JsonTemplateMapper.ReadJsonFromFile <ContainerConfigurationTemplate>(savedConfigPath); Assert.AreEqual("wasm", savedContainerConfig.Architecture); }
/** * Pulls the base image. * * @param registryAuthorization authentication credentials to possibly use * @param progressEventDispatcher the {@link ProgressEventDispatcher} for emitting {@link * ProgressEvent}s * @return the pulled image * @throws IOException when an I/O exception occurs during the pulling * @throws RegistryException if communicating with the registry caused a known error * @throws LayerCountMismatchException if the manifest and configuration contain conflicting layer * information * @throws LayerPropertyNotFoundException if adding image layers fails * @throws BadContainerConfigurationFormatException if the container configuration is in a bad * format */ private async Task <Image> PullBaseImageAsync( Authorization registryAuthorization, ProgressEventDispatcher progressEventDispatcher) { RegistryClient registryClient = buildConfiguration .NewBaseImageRegistryClientFactory() .SetAuthorization(registryAuthorization) .NewRegistryClient(); IManifestTemplate manifestTemplate = await registryClient.PullManifestAsync(buildConfiguration.GetBaseImageConfiguration().GetImageTag()).ConfigureAwait(false); // TODO: Make schema version be enum. switch (manifestTemplate.SchemaVersion) { case 1: V21ManifestTemplate v21ManifestTemplate = (V21ManifestTemplate)manifestTemplate; await buildConfiguration .GetBaseImageLayersCache() .WriteMetadataAsync( buildConfiguration.GetBaseImageConfiguration().GetImage(), v21ManifestTemplate).ConfigureAwait(false); return(JsonToImageTranslator.ToImage(v21ManifestTemplate)); case 2: IBuildableManifestTemplate buildableManifestTemplate = (IBuildableManifestTemplate)manifestTemplate; if (buildableManifestTemplate.GetContainerConfiguration() == null || buildableManifestTemplate.GetContainerConfiguration().Digest == null) { throw new UnknownManifestFormatException( "Invalid container configuration in Docker V2.2/OCI manifest: \n" + JsonTemplateMapper.ToUtf8String(buildableManifestTemplate)); } DescriptorDigest containerConfigurationDigest = buildableManifestTemplate.GetContainerConfiguration().Digest; using (ThrottledProgressEventDispatcherWrapper progressEventDispatcherWrapper = new ThrottledProgressEventDispatcherWrapper( progressEventDispatcher.NewChildProducer(), "pull container configuration " + containerConfigurationDigest)) { string containerConfigurationString = await Blobs.WriteToStringAsync( registryClient.PullBlob( containerConfigurationDigest, progressEventDispatcherWrapper.SetProgressTarget, progressEventDispatcherWrapper.DispatchProgress)).ConfigureAwait(false); ContainerConfigurationTemplate containerConfigurationTemplate = JsonTemplateMapper.ReadJson <ContainerConfigurationTemplate>( containerConfigurationString); await buildConfiguration .GetBaseImageLayersCache() .WriteMetadataAsync( buildConfiguration.GetBaseImageConfiguration().GetImage(), buildableManifestTemplate, containerConfigurationTemplate).ConfigureAwait(false); return(JsonToImageTranslator.ToImage( buildableManifestTemplate, containerConfigurationTemplate)); } } throw new InvalidOperationException(Resources.PullBaseImageStepUnknownManifestErrorMessage); }