···1# this test creates a simple GNU image with docker tools and sees if it executes
23-import ./make-test-python.nix ({ pkgs, ... }: {
00000000000000000000000000000000000000000000004 name = "docker-tools";
5 meta = with pkgs.lib.maintainers; {
6 maintainers = [ lnl7 roberth ];
···219 assert "abc" in docker.succeed(
220 "docker load --input='${examples.layersUnpackOrder}'",
221 "docker run --rm ${examples.layersUnpackOrder.imageName} cat /layer-order"
000000222 )
223224 with subtest("Ensure environment variables are correctly inherited"):
···1# this test creates a simple GNU image with docker tools and sees if it executes
23+import ./make-test-python.nix ({ pkgs, ... }:
4+let
5+ # nixpkgs#214434: dockerTools.buildImage fails to unpack base images
6+ # containing duplicate layers when those duplicate tarballs
7+ # appear under the manifest's 'Layers'. Docker can generate images
8+ # like this even though dockerTools does not.
9+ repeatedLayerTestImage =
10+ let
11+ # Rootfs diffs for layers 1 and 2 are identical (and empty)
12+ layer1 = pkgs.dockerTools.buildImage { name = "empty"; };
13+ layer2 = layer1.overrideAttrs (_: { fromImage = layer1; });
14+ repeatedRootfsDiffs = pkgs.runCommandNoCC "image-with-links.tar" {
15+ nativeBuildInputs = [pkgs.jq];
16+ } ''
17+ mkdir contents
18+ tar -xf "${layer2}" -C contents
19+ cd contents
20+ first_rootfs=$(jq -r '.[0].Layers[0]' manifest.json)
21+ second_rootfs=$(jq -r '.[0].Layers[1]' manifest.json)
22+ target_rootfs=$(sha256sum "$first_rootfs" | cut -d' ' -f 1).tar
23+24+ # Replace duplicated rootfs diffs with symlinks to one tarball
25+ chmod -R ug+w .
26+ mv "$first_rootfs" "$target_rootfs"
27+ rm "$second_rootfs"
28+ ln -s "../$target_rootfs" "$first_rootfs"
29+ ln -s "../$target_rootfs" "$second_rootfs"
30+31+ # Update manifest's layers to use the symlinks' target
32+ cat manifest.json | \
33+ jq ".[0].Layers[0] = \"$target_rootfs\"" |
34+ jq ".[0].Layers[1] = \"$target_rootfs\"" > manifest.json.new
35+ mv manifest.json.new manifest.json
36+37+ tar --sort=name --hard-dereference -cf $out .
38+ '';
39+ in pkgs.dockerTools.buildImage {
40+ fromImage = repeatedRootfsDiffs;
41+ name = "repeated-layer-test";
42+ tag = "latest";
43+ copyToRoot = pkgs.bash;
44+ # A runAsRoot script is required to force previous layers to be unpacked
45+ runAsRoot = ''
46+ echo 'runAsRoot has run.'
47+ '';
48+ };
49+in {
50 name = "docker-tools";
51 meta = with pkgs.lib.maintainers; {
52 maintainers = [ lnl7 roberth ];
···265 assert "abc" in docker.succeed(
266 "docker load --input='${examples.layersUnpackOrder}'",
267 "docker run --rm ${examples.layersUnpackOrder.imageName} cat /layer-order"
268+ )
269+270+ with subtest("Ensure repeated base layers handled by buildImage"):
271+ docker.succeed(
272+ "docker load --input='${repeatedLayerTestImage}'",
273+ "docker run --rm ${repeatedLayerTestImage.imageName} /bin/bash -c 'exit 0'"
274 )
275276 with subtest("Ensure environment variables are correctly inherited"):
+11-1
pkgs/build-support/docker/default.nix
···229 mount /dev/${vmTools.hd} disk
230 cd disk
231000000000232 if [[ -n "$fromImage" ]]; then
233 echo "Unpacking base image..."
234 mkdir image
···245 parentID="$(cat "image/manifest.json" | jq -r '.[0].Config | rtrimstr(".json")')"
246 fi
247248- cat ./image/manifest.json | jq -r '.[0].Layers | .[]' > layer-list
0249 else
250 touch layer-list
251 fi
···229 mount /dev/${vmTools.hd} disk
230 cd disk
231232+ function dedup() {
233+ declare -A seen
234+ while read ln; do
235+ if [[ -z "''${seen["$ln"]:-}" ]]; then
236+ echo "$ln"; seen["$ln"]=1
237+ fi
238+ done
239+ }
240+241 if [[ -n "$fromImage" ]]; then
242 echo "Unpacking base image..."
243 mkdir image
···254 parentID="$(cat "image/manifest.json" | jq -r '.[0].Config | rtrimstr(".json")')"
255 fi
256257+ # In case of repeated layers, unpack only the last occurrence of each
258+ cat ./image/manifest.json | jq -r '.[0].Layers | .[]' | tac | dedup | tac > layer-list
259 else
260 touch layer-list
261 fi