From e5aed4208b7ea3c582cdcd6d34714b3a933d2dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Vl=C3=A9rick?= Date: Thu, 29 Jun 2023 16:24:13 +0200 Subject: [PATCH] Addressing review comments, work on nested image started MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Vlérick --- go.mod | 1 + go.sum | 3 + ...e402ae2e97119c6007b6e52146419985ec1f0092dc | 1 + ...2b8637b47ce96c838ba2aa0de66d14f45cedc11423 | 30 ++ ...b77c933269586ad0226c83405776be08547e4d2a18 | 16 + oci/layout/fixtures/delete_image/index.json | 13 + oci/layout/fixtures/delete_image/oci-layout | 1 + ...9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e | 30 ++ ...fbfbb2141ff5f0f25b033078a4c11fe597770b6fab | 16 + ...2b8637b47ce96c838ba2aa0de66d14f45cedc11423 | 30 ++ ...34a0e5699056536885580ee929945bcbfeaf2633e6 | 1 + ...5597cb0eec8978b07e45a68f782965fd00a8964545 | 1 + ...038c76290d10dbefdb9b2137301c1e867f6f43cff6 | 16 + .../delete_image_multipleimages/index.json | 21 ++ .../delete_image_multipleimages/oci-layout | 1 + ...e402ae2e97119c6007b6e52146419985ec1f0092dc | 1 + ...2b8637b47ce96c838ba2aa0de66d14f45cedc11423 | 30 ++ ...b51f96aa05a3c15eda0aa83dc5d51aa592c776579f | 13 + ...b77c933269586ad0226c83405776be08547e4d2a18 | 16 + .../delete_image_nestedindex/index.json | 10 + .../delete_image_nestedindex/oci-layout | 1 + ...304f42664a0b7d6b0e7cbe72d7a7d72c5dd4e11389 | 16 + ...ac535496a0b7b661311d1fb8ed7a1f51368bfa9f3a | 21 ++ ...4c344034c89a39ef1a451a55b44926ad9ee77e036b | 1 + ...9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e | 30 ++ ...2b8637b47ce96c838ba2aa0de66d14f45cedc11423 | 30 ++ ...33e151a10d2d011ea2222a4412219c5cf2723e6e50 | 16 + ...34a0e5699056536885580ee929945bcbfeaf2633e6 | 1 + ...5597cb0eec8978b07e45a68f782965fd00a8964545 | 1 + .../delete_image_sharedblobs/index.json | 29 ++ .../delete_image_sharedblobs/oci-layout | 1 + oci/layout/oci_transport.go | 7 +- oci/layout/oci_transport_test.go | 282 ++++++------------ 33 files changed, 493 insertions(+), 194 deletions(-) create mode 100644 oci/layout/fixtures/delete_image/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc create mode 100644 oci/layout/fixtures/delete_image/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 create mode 100644 oci/layout/fixtures/delete_image/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 create mode 100644 oci/layout/fixtures/delete_image/index.json create mode 100644 oci/layout/fixtures/delete_image/oci-layout create mode 100644 oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e create mode 100644 oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/9a48d58d496b700f364686fbfbb2141ff5f0f25b033078a4c11fe597770b6fab create mode 100644 oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 create mode 100644 oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6 create mode 100644 oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545 create mode 100644 oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/f082a2f88d9405f9d583e5038c76290d10dbefdb9b2137301c1e867f6f43cff6 create mode 100644 oci/layout/fixtures/delete_image_multipleimages/index.json create mode 100644 oci/layout/fixtures/delete_image_multipleimages/oci-layout create mode 100644 oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc create mode 100644 oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 create mode 100644 oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/c04b22b86e5c1853d9addfb51f96aa05a3c15eda0aa83dc5d51aa592c776579f create mode 100644 oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 create mode 100644 oci/layout/fixtures/delete_image_nestedindex/index.json create mode 100644 oci/layout/fixtures/delete_image_nestedindex/oci-layout create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/11afdbc1155db5c42356e8304f42664a0b7d6b0e7cbe72d7a7d72c5dd4e11389 create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/2363edaccd5115dad0462eac535496a0b7b661311d1fb8ed7a1f51368bfa9f3a create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/49b6418afb4ee08ba3956e4c344034c89a39ef1a451a55b44926ad9ee77e036b create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/bbe511ad9c952a757e832933e151a10d2d011ea2222a4412219c5cf2723e6e50 create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6 create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545 create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/index.json create mode 100644 oci/layout/fixtures/delete_image_sharedblobs/oci-layout diff --git a/go.mod b/go.mod index 768645cedf..7334b2bc4b 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/opencontainers/image-spec v1.1.0-rc4 github.com/opencontainers/selinux v1.11.0 github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f + github.com/otiai10/copy v1.12.0 github.com/proglottis/gpgme v0.1.3 github.com/sigstore/fulcio v1.3.2 github.com/sigstore/rekor v1.2.2 diff --git a/go.sum b/go.sum index 6bcf6c9098..c6fb8e02b7 100644 --- a/go.sum +++ b/go.sum @@ -703,6 +703,9 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f h1:/UDgs8FGMqwnHagNDPGOlts35QkhAZ8by3DR7nMih7M= github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc= +github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY= +github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= +github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= diff --git a/oci/layout/fixtures/delete_image/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc b/oci/layout/fixtures/delete_image/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc new file mode 100644 index 0000000000..e7e64ba41b --- /dev/null +++ b/oci/layout/fixtures/delete_image/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc @@ -0,0 +1 @@ +insert binary content here #9671 diff --git a/oci/layout/fixtures/delete_image/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 b/oci/layout/fixtures/delete_image/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 new file mode 100644 index 0000000000..f0f06201be --- /dev/null +++ b/oci/layout/fixtures/delete_image/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 @@ -0,0 +1,30 @@ +{ + "created": "2019-08-20T20:19:55.211423266Z", + "architecture": "amd64", + "os": "linux", + "config": { + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Cmd": [ + "/bin/sh" + ] + }, + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" + ] + }, + "history": [ + { + "created": "2019-08-20T20:19:55.062606894Z", + "created_by": "/bin/sh -c #(nop) ADD file:fe64057fbb83dccb960efabbf1cd8777920ef279a7fa8dbca0a8801c651bdf7c in / " + }, + { + "created": "2019-08-20T20:19:55.211423266Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", + "empty_layer": true + } + ] +} diff --git a/oci/layout/fixtures/delete_image/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 b/oci/layout/fixtures/delete_image/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 new file mode 100644 index 0000000000..1ff195d0f3 --- /dev/null +++ b/oci/layout/fixtures/delete_image/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423", + "size": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc", + "size": 33 + } + ] +} diff --git a/oci/layout/fixtures/delete_image/index.json b/oci/layout/fixtures/delete_image/index.json new file mode 100644 index 0000000000..49925c19ae --- /dev/null +++ b/oci/layout/fixtures/delete_image/index.json @@ -0,0 +1,13 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18", + "size": 405, + "annotations": { + "org.opencontainers.image.ref.name": "latest" + } + } + ] +} diff --git a/oci/layout/fixtures/delete_image/oci-layout b/oci/layout/fixtures/delete_image/oci-layout new file mode 100644 index 0000000000..21b1439d1c --- /dev/null +++ b/oci/layout/fixtures/delete_image/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion": "1.0.0"} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e new file mode 100644 index 0000000000..311858b5d4 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e @@ -0,0 +1,30 @@ +{ + "created": "2019-01-30T22:20:12.031064202Z", + "architecture": "amd64", + "os": "linux", + "config": { + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Cmd": [ + "/bin/sh" + ] + }, + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:2f0b1957d1f7074296e0d6388139b7a968e8c051f8b6227f3610757f7407af05" + ] + }, + "history": [ + { + "created": "2019-01-30T22:20:11.788749685Z", + "created_by": "/bin/sh -c #(nop) ADD file:3b4be7a9f665764de3067907af34cd36e3755c930cd894821d03d46ebb329812 in / " + }, + { + "created": "2019-01-30T22:20:12.031064202Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", + "empty_layer": true + } + ] +} diff --git a/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/9a48d58d496b700f364686fbfbb2141ff5f0f25b033078a4c11fe597770b6fab b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/9a48d58d496b700f364686fbfbb2141ff5f0f25b033078a4c11fe597770b6fab new file mode 100644 index 0000000000..1bbffe7cf9 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/9a48d58d496b700f364686fbfbb2141ff5f0f25b033078a4c11fe597770b6fab @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e", + "size": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545", + "size": 34 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 new file mode 100644 index 0000000000..f0f06201be --- /dev/null +++ b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 @@ -0,0 +1,30 @@ +{ + "created": "2019-08-20T20:19:55.211423266Z", + "architecture": "amd64", + "os": "linux", + "config": { + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Cmd": [ + "/bin/sh" + ] + }, + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" + ] + }, + "history": [ + { + "created": "2019-08-20T20:19:55.062606894Z", + "created_by": "/bin/sh -c #(nop) ADD file:fe64057fbb83dccb960efabbf1cd8777920ef279a7fa8dbca0a8801c651bdf7c in / " + }, + { + "created": "2019-08-20T20:19:55.211423266Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", + "empty_layer": true + } + ] +} diff --git a/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6 b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6 new file mode 100644 index 0000000000..3a1e4b21e5 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6 @@ -0,0 +1 @@ +insert binary content here #24993 diff --git a/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545 b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545 new file mode 100644 index 0000000000..1cfb0c4c23 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545 @@ -0,0 +1 @@ +insert binary content here #23287 diff --git a/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/f082a2f88d9405f9d583e5038c76290d10dbefdb9b2137301c1e867f6f43cff6 b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/f082a2f88d9405f9d583e5038c76290d10dbefdb9b2137301c1e867f6f43cff6 new file mode 100644 index 0000000000..75a476f2d0 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multipleimages/blobs/sha256/f082a2f88d9405f9d583e5038c76290d10dbefdb9b2137301c1e867f6f43cff6 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423", + "size": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6", + "size": 34 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_multipleimages/index.json b/oci/layout/fixtures/delete_image_multipleimages/index.json new file mode 100644 index 0000000000..74e59f75e1 --- /dev/null +++ b/oci/layout/fixtures/delete_image_multipleimages/index.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:9a48d58d496b700f364686fbfbb2141ff5f0f25b033078a4c11fe597770b6fab", + "size": 405, + "annotations": { + "org.opencontainers.image.ref.name": "3.2" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:f082a2f88d9405f9d583e5038c76290d10dbefdb9b2137301c1e867f6f43cff6", + "size": 405, + "annotations": { + "org.opencontainers.image.ref.name": "3.10.2" + } + } + ] +} diff --git a/oci/layout/fixtures/delete_image_multipleimages/oci-layout b/oci/layout/fixtures/delete_image_multipleimages/oci-layout new file mode 100644 index 0000000000..21b1439d1c --- /dev/null +++ b/oci/layout/fixtures/delete_image_multipleimages/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion": "1.0.0"} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc b/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc new file mode 100644 index 0000000000..e7e64ba41b --- /dev/null +++ b/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc @@ -0,0 +1 @@ +insert binary content here #9671 diff --git a/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 b/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 new file mode 100644 index 0000000000..f0f06201be --- /dev/null +++ b/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 @@ -0,0 +1,30 @@ +{ + "created": "2019-08-20T20:19:55.211423266Z", + "architecture": "amd64", + "os": "linux", + "config": { + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Cmd": [ + "/bin/sh" + ] + }, + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" + ] + }, + "history": [ + { + "created": "2019-08-20T20:19:55.062606894Z", + "created_by": "/bin/sh -c #(nop) ADD file:fe64057fbb83dccb960efabbf1cd8777920ef279a7fa8dbca0a8801c651bdf7c in / " + }, + { + "created": "2019-08-20T20:19:55.211423266Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", + "empty_layer": true + } + ] +} diff --git a/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/c04b22b86e5c1853d9addfb51f96aa05a3c15eda0aa83dc5d51aa592c776579f b/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/c04b22b86e5c1853d9addfb51f96aa05a3c15eda0aa83dc5d51aa592c776579f new file mode 100644 index 0000000000..49925c19ae --- /dev/null +++ b/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/c04b22b86e5c1853d9addfb51f96aa05a3c15eda0aa83dc5d51aa592c776579f @@ -0,0 +1,13 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18", + "size": 405, + "annotations": { + "org.opencontainers.image.ref.name": "latest" + } + } + ] +} diff --git a/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 b/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 new file mode 100644 index 0000000000..1ff195d0f3 --- /dev/null +++ b/oci/layout/fixtures/delete_image_nestedindex/blobs/sha256/eaa95f3cfaac07c8a5153eb77c933269586ad0226c83405776be08547e4d2a18 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423", + "size": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc", + "size": 33 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_nestedindex/index.json b/oci/layout/fixtures/delete_image_nestedindex/index.json new file mode 100644 index 0000000000..1fcf361467 --- /dev/null +++ b/oci/layout/fixtures/delete_image_nestedindex/index.json @@ -0,0 +1,10 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.index.v1+json", + "digest": "sha256:c04b22b86e5c1853d9addfb51f96aa05a3c15eda0aa83dc5d51aa592c776579f", + "size": 1542 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_nestedindex/oci-layout b/oci/layout/fixtures/delete_image_nestedindex/oci-layout new file mode 100644 index 0000000000..21b1439d1c --- /dev/null +++ b/oci/layout/fixtures/delete_image_nestedindex/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion": "1.0.0"} \ No newline at end of file diff --git a/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/11afdbc1155db5c42356e8304f42664a0b7d6b0e7cbe72d7a7d72c5dd4e11389 b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/11afdbc1155db5c42356e8304f42664a0b7d6b0e7cbe72d7a7d72c5dd4e11389 new file mode 100644 index 0000000000..c8f52d491b --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/11afdbc1155db5c42356e8304f42664a0b7d6b0e7cbe72d7a7d72c5dd4e11389 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423", + "size": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545", + "size": 34 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/2363edaccd5115dad0462eac535496a0b7b661311d1fb8ed7a1f51368bfa9f3a b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/2363edaccd5115dad0462eac535496a0b7b661311d1fb8ed7a1f51368bfa9f3a new file mode 100644 index 0000000000..7d7f4a0108 --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/2363edaccd5115dad0462eac535496a0b7b661311d1fb8ed7a1f51368bfa9f3a @@ -0,0 +1,21 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e", + "size": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545", + "size": 34 + }, + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:49b6418afb4ee08ba3956e4c344034c89a39ef1a451a55b44926ad9ee77e036b", + "size": 34 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/49b6418afb4ee08ba3956e4c344034c89a39ef1a451a55b44926ad9ee77e036b b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/49b6418afb4ee08ba3956e4c344034c89a39ef1a451a55b44926ad9ee77e036b new file mode 100644 index 0000000000..1b9ac01844 --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/49b6418afb4ee08ba3956e4c344034c89a39ef1a451a55b44926ad9ee77e036b @@ -0,0 +1 @@ +insert binary content here #25145 diff --git a/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e new file mode 100644 index 0000000000..311858b5d4 --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e @@ -0,0 +1,30 @@ +{ + "created": "2019-01-30T22:20:12.031064202Z", + "architecture": "amd64", + "os": "linux", + "config": { + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Cmd": [ + "/bin/sh" + ] + }, + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:2f0b1957d1f7074296e0d6388139b7a968e8c051f8b6227f3610757f7407af05" + ] + }, + "history": [ + { + "created": "2019-01-30T22:20:11.788749685Z", + "created_by": "/bin/sh -c #(nop) ADD file:3b4be7a9f665764de3067907af34cd36e3755c930cd894821d03d46ebb329812 in / " + }, + { + "created": "2019-01-30T22:20:12.031064202Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", + "empty_layer": true + } + ] +} diff --git a/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 new file mode 100644 index 0000000000..f0f06201be --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423 @@ -0,0 +1,30 @@ +{ + "created": "2019-08-20T20:19:55.211423266Z", + "architecture": "amd64", + "os": "linux", + "config": { + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Cmd": [ + "/bin/sh" + ] + }, + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" + ] + }, + "history": [ + { + "created": "2019-08-20T20:19:55.062606894Z", + "created_by": "/bin/sh -c #(nop) ADD file:fe64057fbb83dccb960efabbf1cd8777920ef279a7fa8dbca0a8801c651bdf7c in / " + }, + { + "created": "2019-08-20T20:19:55.211423266Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", + "empty_layer": true + } + ] +} diff --git a/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/bbe511ad9c952a757e832933e151a10d2d011ea2222a4412219c5cf2723e6e50 b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/bbe511ad9c952a757e832933e151a10d2d011ea2222a4412219c5cf2723e6e50 new file mode 100644 index 0000000000..7ce3a4b83e --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/bbe511ad9c952a757e832933e151a10d2d011ea2222a4412219c5cf2723e6e50 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e", + "size": 585 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6", + "size": 34 + } + ] +} diff --git a/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6 b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6 new file mode 100644 index 0000000000..3a1e4b21e5 --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6 @@ -0,0 +1 @@ +insert binary content here #24993 diff --git a/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545 b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545 new file mode 100644 index 0000000000..1cfb0c4c23 --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/blobs/sha256/d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545 @@ -0,0 +1 @@ +insert binary content here #23287 diff --git a/oci/layout/fixtures/delete_image_sharedblobs/index.json b/oci/layout/fixtures/delete_image_sharedblobs/index.json new file mode 100644 index 0000000000..712f226a73 --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/index.json @@ -0,0 +1,29 @@ +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:2363edaccd5115dad0462eac535496a0b7b661311d1fb8ed7a1f51368bfa9f3a", + "size": 405, + "annotations": { + "org.opencontainers.image.ref.name": "3.2" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:11afdbc1155db5c42356e8304f42664a0b7d6b0e7cbe72d7a7d72c5dd4e11389", + "size": 405, + "annotations": { + "org.opencontainers.image.ref.name": "3.10.2" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:bbe511ad9c952a757e832933e151a10d2d011ea2222a4412219c5cf2723e6e50", + "size": 405, + "annotations": { + "org.opencontainers.image.ref.name": "latest" + } + } + ] +} diff --git a/oci/layout/fixtures/delete_image_sharedblobs/oci-layout b/oci/layout/fixtures/delete_image_sharedblobs/oci-layout new file mode 100644 index 0000000000..21b1439d1c --- /dev/null +++ b/oci/layout/fixtures/delete_image_sharedblobs/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion": "1.0.0"} \ No newline at end of file diff --git a/oci/layout/oci_transport.go b/oci/layout/oci_transport.go index 276aa8c697..cd7283f552 100644 --- a/oci/layout/oci_transport.go +++ b/oci/layout/oci_transport.go @@ -162,7 +162,11 @@ func (ref ociReference) NewImage(ctx context.Context, sys *types.SystemContext) // getIndex returns a pointer to the index references by this ociReference. If an error occurs opening an index nil is returned together // with an error. func (ref ociReference) getIndex() (*imgspecv1.Index, error) { - indexJSON, err := os.Open(ref.indexPath()) + return parseIndex(ref.indexPath()) +} + +func parseIndex(path string) (*imgspecv1.Index, error) { + indexJSON, err := os.Open(path) if err != nil { return nil, err } @@ -275,6 +279,7 @@ func (ref ociReference) DeleteImage(ctx context.Context, sys *types.SystemContex if err != nil { return err } + blobsUsedByOtherImages.Add(otherImageManifest.Config.Digest) for _, layer := range otherImageManifest.Layers { blobsUsedByOtherImages.Add(layer.Digest) } diff --git a/oci/layout/oci_transport_test.go b/oci/layout/oci_transport_test.go index cda632e3b6..56a0ec7e0d 100644 --- a/oci/layout/oci_transport_test.go +++ b/oci/layout/oci_transport_test.go @@ -2,7 +2,8 @@ package layout import ( "context" - "encoding/json" + "fmt" + "io/ioutil" "os" "path/filepath" "testing" @@ -10,8 +11,8 @@ import ( _ "github.com/containers/image/v5/internal/testing/explicitfilepath-tmpdir" "github.com/containers/image/v5/types" "github.com/opencontainers/go-digest" - "github.com/opencontainers/image-spec/specs-go" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" + cp "github.com/otiai10/copy" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -322,108 +323,17 @@ func TestReferenceNewImageDestination(t *testing.T) { defer dest.Close() } -type fakeImageSpec struct { - name string - manifest string - config string - layers []string -} - -func generateOciIndexAndContent(t *testing.T, images ...fakeImageSpec) string { +func loadFixture(t *testing.T, fixtureName string) string { tmpDir := t.TempDir() - - // Create blobs dir - assumption: all the content is sha256 digest-ed - blobsDir := filepath.Join(tmpDir, "blobs", string(digest.SHA256)) - err := os.MkdirAll(blobsDir, 0777) + err := cp.Copy(fmt.Sprintf("fixtures/%v/", fixtureName), tmpDir) require.NoError(t, err) - - saveJson := func(path string, content any) { - file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644) - require.NoError(t, err) - defer file.Close() - - err = json.NewEncoder(file).Encode(content) - require.NoError(t, err) - } - - indexManifests := make([]imgspecv1.Descriptor, 0, len(images)) - - for _, image := range images { - // Create the layers blobs - layers := make([]imgspecv1.Descriptor, 0, len(image.layers)) - - for _, layer := range image.layers { - layerDigest, err := digest.Parse(layer) - require.NoError(t, err) - path := filepath.Join(blobsDir, layerDigest.Hex()) - content := []byte("ABCDEF") - err = os.WriteFile(path, content, 0644) - require.NoError(t, err) - layers = append(layers, imgspecv1.Descriptor{ - MediaType: imgspecv1.MediaTypeImageLayerGzip, - Digest: layerDigest, - }) - } - - // Create the config blob - configDigest, err := digest.Parse(image.config) - require.NoError(t, err) - - config := imgspecv1.Descriptor{} - saveJson(filepath.Join(blobsDir, configDigest.Hex()), config) - - // Create the manifest blob - manifestDigest, err := digest.Parse(image.manifest) - require.NoError(t, err) - - manifest := imgspecv1.Manifest{ - Versioned: specs.Versioned{SchemaVersion: 2}, - MediaType: imgspecv1.MediaTypeImageManifest, - Config: imgspecv1.Descriptor{ - MediaType: imgspecv1.MediaTypeImageConfig, - Digest: configDigest, - Size: 10, - }, - Layers: layers, - } - - saveJson(filepath.Join(blobsDir, manifestDigest.Hex()), manifest) - - // Populate the index - indexManifests = append(indexManifests, imgspecv1.Descriptor{ - MediaType: imgspecv1.MediaTypeImageManifest, - Digest: manifestDigest, - Annotations: map[string]string{ - imgspecv1.AnnotationRefName: image.name, - }, - }) - } - - // Create the index - index := imgspecv1.Index{ - Versioned: specs.Versioned{SchemaVersion: 2}, - Manifests: indexManifests, - } - - saveJson(filepath.Join(tmpDir, "index.json"), index) - return tmpDir } func TestReferenceDeleteImage(t *testing.T) { - image := fakeImageSpec{ - name: "image-1:latest", - manifest: "sha256:7df521835a17f9308c7d89484c6f6c630f6d5ed7126df8485f0e6ec0ec1cc9bc", - config: "sha256:d0cc41b6cef5cc972a521ce9b81995c39533f2430df03cb62f44799b15d21217", - layers: []string{ - "sha256:ebfb402c523af279c1b58751b9c3c48d250906f4e57ef8af4fc0540e290281dc", - "sha256:f37ee95567a8ca93744f71634155b45ac405f509fa1e5d1a497b36a54619be56", - }, - } + tmpDir := loadFixture(t, "delete_image") - tmpDir := generateOciIndexAndContent(t, []fakeImageSpec{image}...) - - ref, err := NewReference(tmpDir, image.name) + ref, err := NewReference(tmpDir, "latest") require.NoError(t, err) err = ref.DeleteImage(context.Background(), nil) @@ -431,11 +341,9 @@ func TestReferenceDeleteImage(t *testing.T) { // Check that all blobs were deleted blobsDir := filepath.Join(tmpDir, "blobs") - blobDoesNotExist(t, blobsDir, image.manifest) - blobDoesNotExist(t, blobsDir, image.config) - for _, layer := range image.layers { - blobDoesNotExist(t, blobsDir, layer) - } + files, err := ioutil.ReadDir(filepath.Join(blobsDir, "sha256")) + require.NoError(t, err) + require.Empty(t, files) // Check that the index doesn't contain the reference anymore ociRef, ok := ref.(ociReference) @@ -450,16 +358,7 @@ func TestReferenceDeleteImage(t *testing.T) { } func TestReferenceDeleteImage_emptyImageName(t *testing.T) { - image := fakeImageSpec{ - name: "image-1:latest", - manifest: "sha256:7df521835a17f9308c7d89484c6f6c630f6d5ed7126df8485f0e6ec0ec1cc9bc", - config: "sha256:d0cc41b6cef5cc972a521ce9b81995c39533f2430df03cb62f44799b15d21217", - layers: []string{ - "sha256:ebfb402c523af279c1b58751b9c3c48d250906f4e57ef8af4fc0540e290281dc", - }, - } - - tmpDir := generateOciIndexAndContent(t, []fakeImageSpec{image}...) + tmpDir := loadFixture(t, "delete_image") ref, err := NewReference(tmpDir, "") require.NoError(t, err) @@ -469,11 +368,9 @@ func TestReferenceDeleteImage_emptyImageName(t *testing.T) { // Check that all blobs were deleted blobsDir := filepath.Join(tmpDir, "blobs") - blobDoesNotExist(t, blobsDir, image.manifest) - blobDoesNotExist(t, blobsDir, image.config) - for _, layer := range image.layers { - blobDoesNotExist(t, blobsDir, layer) - } + files, err := ioutil.ReadDir(filepath.Join(blobsDir, "sha256")) + require.NoError(t, err) + require.Empty(t, files) // Check that the index doesn't contain the reference anymore ociRef, ok := ref.(ociReference) @@ -481,107 +378,77 @@ func TestReferenceDeleteImage_emptyImageName(t *testing.T) { index, err := ociRef.getIndex() require.NoError(t, err) for _, v := range index.Manifests { - if v.Annotations[imgspecv1.AnnotationRefName] == image.name { + if v.Annotations[imgspecv1.AnnotationRefName] == ociRef.image { assert.Fail(t, "image still present in the index after deletion") } } } -func TestReferenceDeleteImage_emptyImageNameButMoreThanOneImageInIndex(t *testing.T) { - images := []fakeImageSpec{ - { - name: "image-1:latest", - manifest: "sha256:7df521835a17f9308c7d89484c6f6c630f6d5ed7126df8485f0e6ec0ec1cc9bc", - config: "sha256:d0cc41b6cef5cc972a521ce9b81995c39533f2430df03cb62f44799b15d21217", - layers: []string{ - "sha256:ebfb402c523af279c1b58751b9c3c48d250906f4e57ef8af4fc0540e290281dc", - }, - }, - { - name: "image-2:latest", - manifest: "sha256:b4679e9e04b749cab43f1534ae5c82a521b745c6346b90a7034ca72d3ed38beb", - config: "sha256:eb6bea08ad372676ed419b424557f517e9b5190b0af38614cb30548908fcf794", - layers: []string{ - "sha256:623802888f95381343c8511943d774b6ac96ff8710fc40b7b47845a50d038c2c", - }, - }, - } +func TestReferenceDeleteImage_imageDoesNotExist(t *testing.T) { + tmpDir := loadFixture(t, "delete_image") - tmpDir := generateOciIndexAndContent(t, images...) + ref, err := NewReference(tmpDir, "does-not-exist") + assert.NoError(t, err) - ref, err := NewReference(tmpDir, "") + err = ref.DeleteImage(context.Background(), nil) + assert.Error(t, err) +} + +func TestReferenceDeleteImage_moreThanOneImageInIndex(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_multipleimages") + + ref, err := NewReference(tmpDir, "3.2") require.NoError(t, err) err = ref.DeleteImage(context.Background(), nil) - require.Error(t, err) -} + require.NoError(t, err) -func TestReferenceDeleteImage_imageDoesNotExist(t *testing.T) { - image := fakeImageSpec{ - name: "image-1:latest", - manifest: "sha256:7df521835a17f9308c7d89484c6f6c630f6d5ed7126df8485f0e6ec0ec1cc9bc", - config: "sha256:d0cc41b6cef5cc972a521ce9b81995c39533f2430df03cb62f44799b15d21217", - layers: []string{ - "sha256:ebfb402c523af279c1b58751b9c3c48d250906f4e57ef8af4fc0540e290281dc", - "sha256:f37ee95567a8ca93744f71634155b45ac405f509fa1e5d1a497b36a54619be56", - }, + // Check that the relevant blobs were deleted/preservend + blobsDir := filepath.Join(tmpDir, "blobs") + blobDoesNotExist(t, blobsDir, "sha256:9a48d58d496b700f364686fbfbb2141ff5f0f25b033078a4c11fe597770b6fab") // menifest of the deleted image + blobDoesNotExist(t, blobsDir, "sha256:8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e") // config of the deleted image + blobDoesNotExist(t, blobsDir, "sha256:d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545") // layer of the deleted image + blobExists(t, blobsDir, "sha256:f082a2f88d9405f9d583e5038c76290d10dbefdb9b2137301c1e867f6f43cff6") // manifest of the other image present in the index + blobExists(t, blobsDir, "sha256:a527179158cd5cebc11c152b8637b47ce96c838ba2aa0de66d14f45cedc11423") // config of the other image present in the index + blobExists(t, blobsDir, "sha256:bc584603ae5ca55d701f5134a0e5699056536885580ee929945bcbfeaf2633e6") // layer of the other image present in the index + + // Check that the index doesn't contain the reference anymore + ociRef, ok := ref.(ociReference) + require.True(t, ok) + index, err := ociRef.getIndex() + require.NoError(t, err) + for _, v := range index.Manifests { + if v.Annotations[imgspecv1.AnnotationRefName] == ociRef.image { + assert.Fail(t, "image still present in the index after deletion") + } } +} - tmpDir := generateOciIndexAndContent(t, []fakeImageSpec{image}...) +func TestReferenceDeleteImage_emptyImageNameButMoreThanOneImageInIndex(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_multipleimages") - ref, err := NewReference(tmpDir, "does-not:exist") - assert.NoError(t, err) + ref, err := NewReference(tmpDir, "") + require.NoError(t, err) err = ref.DeleteImage(context.Background(), nil) - assert.Error(t, err) + require.Error(t, err) } func TestReferenceDeleteImage_someLayersAreReferencedByOtherImages(t *testing.T) { - const commonLayer = "sha256:bff18d814a6d85fb3ea9b1ee7271b831e204ff0bd88a17c4bfcf9a83ed07e8f8" - images := []fakeImageSpec{ - { - name: "image-1:latest", - manifest: "sha256:7df521835a17f9308c7d89484c6f6c630f6d5ed7126df8485f0e6ec0ec1cc9bc", - config: "sha256:d0cc41b6cef5cc972a521ce9b81995c39533f2430df03cb62f44799b15d21217", - layers: []string{ - "sha256:ebfb402c523af279c1b58751b9c3c48d250906f4e57ef8af4fc0540e290281dc", - commonLayer, - "sha256:f37ee95567a8ca93744f71634155b45ac405f509fa1e5d1a497b36a54619be56", - }, - }, - { - name: "image-2:latest", - manifest: "sha256:b4679e9e04b749cab43f1534ae5c82a521b745c6346b90a7034ca72d3ed38beb", - config: "sha256:eb6bea08ad372676ed419b424557f517e9b5190b0af38614cb30548908fcf794", - layers: []string{ - "sha256:623802888f95381343c8511943d774b6ac96ff8710fc40b7b47845a50d038c2c", - commonLayer, - "sha256:66a79b735a97ede9e52267492df7c4a7ee6e287113efe3e7def0c6f73f158589", - }, - }, - } - - tmpDir := generateOciIndexAndContent(t, images...) + tmpDir := loadFixture(t, "delete_image_sharedblobs") - image := images[0] - ref, err := NewReference(tmpDir, image.name) + ref, err := NewReference(tmpDir, "3.2") require.NoError(t, err) err = ref.DeleteImage(context.Background(), nil) require.NoError(t, err) - // Check that all relevant blobs were deleted + // Check that the relevant blobs were deleted/preserved blobsDir := filepath.Join(tmpDir, "blobs") - blobDoesNotExist(t, blobsDir, image.manifest) - blobDoesNotExist(t, blobsDir, image.config) - blobDoesNotExist(t, blobsDir, image.layers[0]) - blobDoesNotExist(t, blobsDir, image.layers[2]) - - // Check that the blob used by another image was not deleted - commonBlobDigest, err := digest.Parse(commonLayer) - require.NoError(t, err) - _, err = os.Stat(filepath.Join(blobsDir, commonBlobDigest.Algorithm().String(), commonBlobDigest.Hex())) - require.NoError(t, err) + blobDoesNotExist(t, blobsDir, "sha256:2363edaccd5115dad0462eac535496a0b7b661311d1fb8ed7a1f51368bfa9f3a") // manifest for the image + blobExists(t, blobsDir, "sha256:8f891520c22dc085f86a1a9aef2e1165e63e7465ae2112df6bd1d7a115a12f8e") // configuration, used by another image too + blobExists(t, blobsDir, "sha256:d107df792639f1ee2fc4555597cb0eec8978b07e45a68f782965fd00a8964545") // layer, used by another image too + blobDoesNotExist(t, blobsDir, "sha256:49b6418afb4ee08ba3956e4c344034c89a39ef1a451a55b44926ad9ee77e036b") // layer used by that image only // Check that the index doesn't contain the reference anymore ociRef, ok := ref.(ociReference) @@ -589,12 +456,33 @@ func TestReferenceDeleteImage_someLayersAreReferencedByOtherImages(t *testing.T) index, err := ociRef.getIndex() require.NoError(t, err) for _, v := range index.Manifests { - if v.Annotations[imgspecv1.AnnotationRefName] == image.name { + if v.Annotations[imgspecv1.AnnotationRefName] == ociRef.image { assert.Fail(t, "image still present in the index after deletion") } } } +func TestReferenceDeleteImage_inNestedIndex(t *testing.T) { + tmpDir := loadFixture(t, "delete_image_nestedindex") + + ref, err := NewReference(tmpDir, "latest") + require.NoError(t, err) + + err = ref.DeleteImage(context.Background(), nil) + require.NoError(t, err) + + // Check that all blobs were deleted + blobsDir := filepath.Join(tmpDir, "blobs") + blobDoesNotExist(t, blobsDir, "sha256:0c8b263642b51b5c1dc40fe402ae2e97119c6007b6e52146419985ec1f0092dc") + blobDoesNotExist(t, blobsDir, "sha256:1f97f0559cbddbff6c872039e93f18c1abdc279cbe82e0eb40258c28f4c30bfd") + blobDoesNotExist(t, blobsDir, "sha256:53ba123023095900727503b971a736d6afaf2dbd02a104a67617ca249abe011f") + + // Check that the index doesn't contain the reference anymore + // ... index is not the index.json but the blob referenced in the index.json + // ... at that point, since the nested index's content has changed, its sha256 too + // ... so it needs to be renamed and index.json has to be updated too +} + func TestReferenceOCILayoutPath(t *testing.T) { ref, tmpDir := refToTempOCI(t) ociRef, ok := ref.(ociReference) @@ -641,6 +529,14 @@ func TestReferenceBlobPathInvalid(t *testing.T) { assert.ErrorContains(t, err, "unexpected digest reference "+hex) } +func blobExists(t *testing.T, blobsDir string, blobDigest string) { + digest, err := digest.Parse(blobDigest) + require.NoError(t, err) + blobPath := filepath.Join(blobsDir, digest.Algorithm().String(), digest.Hex()) + _, err = os.Stat(blobPath) + require.NoError(t, err) +} + func blobDoesNotExist(t *testing.T, blobsDir string, blobDigest string) { digest, err := digest.Parse(blobDigest) require.NoError(t, err)