Skip to content

Commit ea1f2d1

Browse files
committed
Fix Docker and tarball publishing by making sure layer digests get into the manifest json
1 parent 4b78988 commit ea1f2d1

File tree

5 files changed

+41
-12
lines changed

5 files changed

+41
-12
lines changed

src/Containers/Microsoft.NET.Build.Containers/ImageConfig.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ internal void AddLayer(Layer l)
217217
_rootFsLayers.Add(l.Descriptor.UncompressedDigest!);
218218
}
219219

220-
internal void SetUser(string user, bool isUserInteraction = false) {
220+
internal void SetUser(string user, bool isUserInteraction = false)
221+
{
221222
// we don't let automatic/inferred user settings overwrite an explicit user request
222223
if (_userHasBeenExplicitlySet && !isUserInteraction)
223224
{

src/Containers/Microsoft.NET.Build.Containers/Layer.cs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@ internal Layer(FileInfo backingFile, Descriptor descriptor)
4949

5050
public static Layer FromDescriptor(Descriptor descriptor, ContentStore store)
5151
{
52-
return new(new(store.PathForDescriptor(descriptor)), descriptor);
52+
FileInfo path = new(store.PathForDescriptor(descriptor));
53+
return FromBackingFile(path, descriptor);
54+
}
55+
56+
public static Layer FromBackingFile(FileInfo backingFile, Descriptor descriptor)
57+
{
58+
return new(backingFile, descriptor);
5359
}
5460

5561
public static async Task<Layer> FromFiles((string absPath, string relPath)[] inputFiles, string containerPath, bool isWindowsLayer, string manifestMediaType, ContentStore store, FileInfo layerWritePath, CancellationToken ct)
@@ -219,13 +225,16 @@ private sealed class HashDigestGZipStream : Stream
219225
private readonly IncrementalHash sha256Hash;
220226
private readonly GZipStream compressionStream;
221227

222-
public HashDigestGZipStream(Stream writeStream, bool leaveOpen)
228+
public HashDigestGZipStream(Stream writeStream, bool leaveOpen, CompressionMode compressionMode = CompressionMode.Compress)
229+
: base()
223230
{
224231
sha256Hash = IncrementalHash.CreateHash(HashAlgorithmName.SHA256);
225-
compressionStream = new GZipStream(writeStream, CompressionMode.Compress, leaveOpen);
232+
compressionStream = new GZipStream(writeStream, compressionMode, leaveOpen);
226233
}
227234

228-
public override bool CanWrite => true;
235+
public override bool CanWrite => compressionStream.CanWrite;
236+
public override bool CanRead => compressionStream.CanRead;
237+
public override bool CanSeek => compressionStream.CanSeek;
229238

230239
public override void Write(byte[] buffer, int offset, int count)
231240
{
@@ -271,12 +280,30 @@ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationTo
271280
return compressionStream.WriteAsync(buffer, cancellationToken);
272281
}
273282

274-
public override bool CanRead => false;
275-
public override bool CanSeek => false;
276283
public override long Length => throw new NotImplementedException();
277284
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
278285

279-
public override int Read(byte[] buffer, int offset, int count) => throw new NotImplementedException();
286+
public override int Read(byte[] buffer, int offset, int count)
287+
{
288+
var read = compressionStream.Read(buffer, offset, count);
289+
sha256Hash.AppendData(buffer.AsSpan(offset, read));
290+
return read;
291+
}
292+
293+
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
294+
{
295+
var read = compressionStream.ReadAsync(buffer, offset, count, cancellationToken);
296+
sha256Hash.AppendData(buffer.AsSpan(offset, read.Result));
297+
return read;
298+
}
299+
300+
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
301+
{
302+
var read = compressionStream.ReadAsync(buffer, cancellationToken);
303+
sha256Hash.AppendData(buffer.Span.Slice(0, read.Result));
304+
return read;
305+
}
306+
280307
public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException();
281308
public override void SetLength(long value) => throw new NotImplementedException();
282309
}

src/Containers/Microsoft.NET.Build.Containers/LocalDaemons/DockerCli.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,15 +363,16 @@ CancellationToken cancellationToken
363363
cancellationToken.ThrowIfCancellationRequested();
364364
using TarWriter writer = new(imageStream, TarEntryFormat.Pax, leaveOpen: true);
365365
// Feed each layer tarball into the stream
366-
JsonArray layerTarballPaths = new();
367-
await WriteImageLayers(writer, pushData.layers, l => $"{l.Descriptor.Digest.Substring("sha256:".Length)}/layer.tar", cancellationToken)
366+
var layerTarballPathFunc = (Layer l) => $"{l.Descriptor.Digest.Substring("sha256:".Length)}/layer.tar";
367+
await WriteImageLayers(writer, pushData.layers, layerTarballPathFunc, cancellationToken)
368368
.ConfigureAwait(false);
369369

370370
string configTarballPath = $"{pushData.configDigest.Split(':')[1]!}.json";
371371
await WriteImageConfig(writer, pushData.imageConfig, configTarballPath, cancellationToken)
372372
.ConfigureAwait(false);
373373

374374
// Add manifest
375+
JsonArray layerTarballPaths = new JsonArray([.. pushData.layers.Select(layerTarballPathFunc).Select(s => JsonValue.Create(s))]);
375376
await WriteManifestForDockerImage(writer, pushData.repository, pushData.tags, configTarballPath, layerTarballPaths, cancellationToken)
376377
.ConfigureAwait(false);
377378
}

src/Containers/Microsoft.NET.Build.Containers/Tasks/MakeContainerTarball.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public async Task<bool> ExecuteAsync()
4949
(long manifestSize, string manifestDigest, ManifestV2 manifestStructure) = await ReadManifest();
5050
var configDigest = manifestStructure.Config.digest;
5151
var config = await JsonSerializer.DeserializeAsync<JsonObject>(File.OpenRead(Configuration.ItemSpec), cancellationToken: _cts.Token);
52-
var layers = Layers.Select(l => new Layer(new(l.ItemSpec), GetDescriptor(l))).ToArray();
52+
var layers = Layers.Select(l => Layer.FromBackingFile(new(l.ItemSpec), GetDescriptor(l))).ToArray();
5353
var filePath = DetermineFilePath();
5454
await using var fileStream = File.Create(filePath);
5555
GeneratedArchiveFilePath = filePath;

src/Containers/Microsoft.NET.Build.Containers/Tasks/PushContainerToLocal.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public async Task<bool> ExecuteAsync()
5555
return false;
5656
}
5757

58-
var layers = Layers.Select(l => new Layer(new(l.ItemSpec), GetDescriptor(l))).ToArray();
58+
var layers = Layers.Select(l => Layer.FromBackingFile(new(l.ItemSpec), GetDescriptor(l))).ToArray();
5959
try
6060
{
6161
await containerCli.LoadAsync((Repository, Tags, configDigest, config!, layers), DockerCli.WriteDockerImageToStreamAsync, _cts.Token);

0 commit comments

Comments
 (0)