public async Task PushArtifactAsync(Configuration.RootConfiguration configuration, OciArtifactModuleReference moduleReference, StreamDescriptor config, params StreamDescriptor[] layers) { // TODO: How do we choose this? Does it ever change? var algorithmIdentifier = DescriptorFactory.AlgorithmIdentifierSha256; var blobClient = this.CreateBlobClient(configuration, moduleReference); config.ResetStream(); var configDescriptor = DescriptorFactory.CreateDescriptor(algorithmIdentifier, config); config.ResetStream(); var configUploadResult = await blobClient.UploadBlobAsync(config.Stream); var layerDescriptors = new List <OciDescriptor>(layers.Length); foreach (var layer in layers) { layer.ResetStream(); var layerDescriptor = DescriptorFactory.CreateDescriptor(algorithmIdentifier, layer); layerDescriptors.Add(layerDescriptor); layer.ResetStream(); var layerUploadResult = await blobClient.UploadBlobAsync(layer.Stream); } var manifest = new OciManifest(2, configDescriptor, layerDescriptors); using var manifestStream = new MemoryStream(); OciSerialization.Serialize(manifestStream, manifest); manifestStream.Position = 0; // BUG: the client closes the stream :( (is it still the case?) var manifestUploadResult = await blobClient.UploadManifestAsync(manifestStream, new UploadManifestOptions { Tag = moduleReference.Tag }); }
private static OciManifest DeserializeManifest(Stream stream) { try { return(OciSerialization.Deserialize <OciManifest>(stream)); } catch (Exception exception) { throw new InvalidModuleException("Unable to deserialize the module manifest.", exception); } }
protected override void WriteModuleContent(OciArtifactModuleReference reference, OciArtifactResult result) { /* * this should be kept in sync with the IsModuleRestoreRequired() implementation */ // write main.bicep this.FileResolver.Write(this.GetModuleFileUri(reference, ModuleFileType.ModuleMain), result.ModuleStream); // write manifest // it's important to write the original stream here rather than serialize the manifest object // this way we guarantee the manifest hash will match this.FileResolver.Write(this.GetModuleFileUri(reference, ModuleFileType.Manifest), result.ManifestStream); // write metadata var metadata = new ModuleMetadata(result.ManifestDigest); using var metadataStream = new MemoryStream(); OciSerialization.Serialize(metadataStream, metadata); metadataStream.Position = 0; this.FileResolver.Write(this.GetModuleFileUri(reference, ModuleFileType.Metadata), metadataStream); }
public AndConstraint <MockRegistryAssertions> HaveModule(string tag, Stream expectedModuleContent) { using (new AssertionScope()) { this.Subject.ManifestTags.Should().ContainKey(tag, $"tag '{tag}' should exist"); string manifestDigest = this.Subject.ManifestTags[tag]; this.Subject.Manifests.Should().ContainKey(manifestDigest, $"tag '{tag}' resolves to digest '{manifestDigest}' that should exist"); var manifestBytes = this.Subject.Manifests[manifestDigest]; using var manifestStream = MockRegistryBlobClient.WriteStream(manifestBytes); var manifest = OciSerialization.Deserialize <OciManifest>(manifestStream); var config = manifest.Config; config.MediaType.Should().Be("application/vnd.ms.bicep.module.config.v1+json", "config media type should be correct"); config.Size.Should().Be(0, "config should be empty"); this.Subject.Blobs.Should().ContainKey(config.Digest, "config digest should exist"); var configBytes = this.Subject.Blobs[config.Digest]; configBytes.Should().BeEmpty("config should be empty"); manifest.Layers.Should().HaveCount(1, "modules should have a single layer"); var layer = manifest.Layers.Single(); layer.MediaType.Should().Be("application/vnd.ms.bicep.module.layer.v1+json", "layer media type should be correct"); this.Subject.Blobs.Should().ContainKey(layer.Digest); var layerBytes = this.Subject.Blobs[layer.Digest]; ((long)layerBytes.Length).Should().Be(layer.Size); var actual = MockRegistryBlobClient.WriteStream(layerBytes).FromJsonStream <JToken>(); var expected = expectedModuleContent.FromJsonStream <JToken>(); actual.Should().DeepEqual(expected, "module content should match"); } return(new(this)); }