From b619356907b5b0314f0a141dd1c05242dfb0f85b Mon Sep 17 00:00:00 2001 From: jakedt <jacob.moshenko@gmail.com> Date: Sun, 16 Feb 2014 17:38:47 -0500 Subject: [PATCH] Get the base image stuff working. Checkpoint before fixing the tests. --- data/database.py | 23 +- data/model.py | 348 ++++++++++-------- endpoints/api.py | 23 +- endpoints/index.py | 8 +- endpoints/registry.py | 111 ++++-- initdb.py | 13 +- storage/basestorage.py | 3 - .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 .../diffs.json | 0 test/data/test.db | Bin 142336 -> 152576 bytes tools/backfill_commands.py | 20 - tools/backfillsizes.py | 17 - 120 files changed, 305 insertions(+), 261 deletions(-) rename test/data/registry/{images/devtable/complex/c3d710edbd3be254a2bfe7e27a7f47fdc3d710edbd3be254a2bfe7e27a7f47fd => sharedimages/01ca8e73-1961-40d9-bf1f-96cb90564c0b}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/14c839f5acd4b9ed0929c60f6ad8b6ec14c839f5acd4b9ed0929c60f6ad8b6ec => sharedimages/0e778f76-42fb-4d77-a538-03f3a323fcd2}/diffs.json (100%) rename test/data/registry/{images/devtable/complex/24aadc03801e2ca87ba34337b7df1df324aadc03801e2ca87ba34337b7df1df3 => sharedimages/0f16ed5a-59d3-4b59-953d-c441dc6d77d2}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/25f3f74ae1cdb37cd5e7fbf4b29f42d825f3f74ae1cdb37cd5e7fbf4b29f42d8 => sharedimages/10d8eae0-28f6-45ce-b103-53cc2f59b674}/diffs.json (100%) rename test/data/registry/{images/devtable/complex/d3acf10ce5ad8b208ba38e626ced2946d3acf10ce5ad8b208ba38e626ced2946 => sharedimages/1508e485-e94f-4154-87c1-53a147ff2c21}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/0ccb6d859cbdf08f5c71132707e144fc0ccb6d859cbdf08f5c71132707e144fc => sharedimages/16b2c776-20b0-426d-81c8-53abe0026706}/diffs.json (100%) rename test/data/registry/{images/buynlarge/orgrepo/5159d2eda87bc26f91e9b7bd0ce73f695159d2eda87bc26f91e9b7bd0ce73f69 => sharedimages/17197704-0e3f-4829-99f2-e246787661a8}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/2561f1d3a276103635c2cde5a7dc77592561f1d3a276103635c2cde5a7dc7759 => sharedimages/2929a979-08c3-44bf-8471-c2bda1ee55ac}/diffs.json (100%) rename test/data/registry/{images/devtable/complex/a4efbdc85fca8ab9db85bf6cbd54b154a4efbdc85fca8ab9db85bf6cbd54b154 => sharedimages/2b11f03d-719c-4a5f-a8fb-f5573ecda5ca}/diffs.json (100%) rename test/data/registry/{images/devtable/complex/5762f8352fb68b3baf43cee20946da815762f8352fb68b3baf43cee20946da81 => sharedimages/2ddcc4ed-0a3f-400b-861c-b16f61e3d54e}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/22d54e9c626a2aa258e5185dc315d5a022d54e9c626a2aa258e5185dc315d5a0 => sharedimages/305f4299-676e-4a2e-953a-cd299bb1a4c0}/diffs.json (100%) rename test/data/registry/{images/devtable/complex/bfbba189913c9454c3e26b62b91bb906bfbba189913c9454c3e26b62b91bb906 => sharedimages/3408fccf-3d90-4e05-9d6e-5cbbd459330a}/diffs.json (100%) rename test/data/registry/{images/buynlarge/orgrepo/0abe0a670562d152243c92280507c7e00abe0a670562d152243c92280507c7e0 => sharedimages/353bd7fe-246a-43b5-a978-7da35c23f6ad}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/1f9c4e12e13735668f2f2b5ebed92a271f9c4e12e13735668f2f2b5ebed92a27 => sharedimages/358d33f4-63ff-4767-95a8-3d524d685bce}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/425c8ea110720bca7fd14e57a59921d8425c8ea110720bca7fd14e57a59921d8 => sharedimages/3825fa0f-5918-4da4-b56c-921f8e88d3f0}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/215cde86f7910181c2b480eddacc55f6215cde86f7910181c2b480eddacc55f6 => sharedimages/3dc8dc91-b7c6-41d8-a74f-ab7d6d949ec0}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/e072d8d21d7dd0b73004258dbabc038de072d8d21d7dd0b73004258dbabc038d => sharedimages/3ea3578c-f04b-4804-8bbf-821c3f1d6d18}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/43839fc1f7d7167236871fac6b0bc26043839fc1f7d7167236871fac6b0bc260 => sharedimages/4d2e5054-bfc3-4b4f-8135-4f03b5e69b53}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/b4edeedb5eb9a0322f224452b69bd545b4edeedb5eb9a0322f224452b69bd545 => sharedimages/4de57937-8f5f-44ff-80b8-387eb4ffb469}/diffs.json (100%) rename test/data/registry/{images/buynlarge/orgrepo/a99fd6afd29cd0ed2d6eb03f4ef8c3aca99fd6afd29cd0ed2d6eb03f4ef8c3ac => sharedimages/4f16ecc7-c2bc-427c-9894-28cb50ff04e1}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/1dcf485dfbdf2ee735d39f74d4ec91321dcf485dfbdf2ee735d39f74d4ec9132 => sharedimages/5012c7dd-524a-4125-affc-c2b424a7f011}/diffs.json (100%) rename test/data/registry/{images/devtable/complex/333b7df80772c6336de9b3fc595649e6333b7df80772c6336de9b3fc595649e6 => sharedimages/5072be66-6816-4f5e-a597-bd981d864768}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/5feb1289afba113e86027d8e1221ebd15feb1289afba113e86027d8e1221ebd1 => sharedimages/50780ff3-75cc-4ad3-a762-5336892b1bd8}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/850c91f203b9eb1b83b3d2097f9a0c29850c91f203b9eb1b83b3d2097f9a0c29 => sharedimages/51817c4b-997b-4afe-925a-99f84876e0b1}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/47f6628f60a012e10865362cfaf3625a47f6628f60a012e10865362cfaf3625a => sharedimages/52e82877-fd84-4202-bacb-88df0e7d0da6}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/a742734a834f9049c373316825e6ab8ea742734a834f9049c373316825e6ab8e => sharedimages/532ac01a-d62d-4b8f-8e73-a6bee7a24455}/diffs.json (100%) rename test/data/registry/{images/devtable/shared/fb820a41a1b0f94cf779305c2e23d4d1fb820a41a1b0f94cf779305c2e23d4d1 => sharedimages/53796278-cce8-4e4d-9ba3-c911f9f1fd81}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/6474104fec6385f173ee7cc4346ba1716474104fec6385f173ee7cc4346ba171 => sharedimages/5707dbfe-09e1-450b-89e5-284a96d640d1}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/5c0b2f2fede746349355d608b07904735c0b2f2fede746349355d608b0790473 => sharedimages/57a9a644-ff7c-4578-9f1e-d39e17e86e50}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/0e621287d1eb7c094af178a9c54ef5f10e621287d1eb7c094af178a9c54ef5f1 => sharedimages/588a6ca4-9403-4f28-a1c2-9807c70cad7e}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/b2a795ca9198e911c359f2b90e75973db2a795ca9198e911c359f2b90e75973d => sharedimages/59bd87db-6c0d-4fe0-b6c3-c4b5fa966c64}/diffs.json (100%) rename test/data/registry/{images/buynlarge/orgrepo/ec0dd7fc4e4c5cf34b2a24dc03ed74b9ec0dd7fc4e4c5cf34b2a24dc03ed74b9 => sharedimages/5a380fa9-72b6-4ca4-bf12-e3ba606f439d}/diffs.json (100%) rename test/data/registry/{images/devtable/complex/85f3f40271af0a032ec07aec57eedf9185f3f40271af0a032ec07aec57eedf91 => sharedimages/5b07deb6-4319-437c-867f-19de0a2a789e}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/c9a19e9e3661af8be048a7e0fbd75ecec9a19e9e3661af8be048a7e0fbd75ece => sharedimages/5bb9536c-0452-46f6-9e07-b940e6438e8f}/diffs.json (100%) rename test/data/registry/{images/devtable/complex/22d1aaa0bc26d6ce091069aaf97ab11d22d1aaa0bc26d6ce091069aaf97ab11d => sharedimages/5d130ed2-57da-464b-bd7f-6dcbbb9d21d6}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/7ebb2eae1ecf7a46ef6d7401c16c6fcd7ebb2eae1ecf7a46ef6d7401c16c6fcd => sharedimages/5f813e36-f439-44ee-aa2f-d5171f37e9e8}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/aa954e497de27864883678892fe00389aa954e497de27864883678892fe00389 => sharedimages/6165db2e-a725-4f09-83f6-ac391620c631}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/5b4f83a3bb31df974c281eaeba38d2cf5b4f83a3bb31df974c281eaeba38d2cf => sharedimages/6306add6-1dc3-4cdc-a11d-0ff8a57521f9}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/6f07844f49df64d3f98b33c7cebc11cf6f07844f49df64d3f98b33c7cebc11cf => sharedimages/66dc45e9-1687-4cb6-a850-ac8c847ae547}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/f52f7ded0612cff3e638da941ac53441f52f7ded0612cff3e638da941ac53441 => sharedimages/6af86670-4135-4d3f-b96b-c80c1e3c195f}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/c913951ea0cd4c6206f10aef139818f6c913951ea0cd4c6206f10aef139818f6 => sharedimages/6b1c1f88-7c8b-4b01-8078-d8a11c836cd2}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/d935480ec258b7e5f5ff21013ee402a6d935480ec258b7e5f5ff21013ee402a6 => sharedimages/6cd9e738-2282-4c7b-acaf-ecc1075e200d}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/69df2430f958b4532bca77f61438c39669df2430f958b4532bca77f61438c396 => sharedimages/6d0ee75b-2116-45c5-acb2-a068fa5c3eaa}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/7f89233fc020acaf004fb7e4d293ae6f7f89233fc020acaf004fb7e4d293ae6f => sharedimages/6e0bbb9f-3d2e-460c-8560-18fdecfc02a2}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/ee43c0adbd6004f2fa0c91af80229849ee43c0adbd6004f2fa0c91af80229849 => sharedimages/759c8017-ae45-4cdb-8bb1-798870dc0bfa}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/77e619ad5684dac98971aae11fb4925677e619ad5684dac98971aae11fb49256 => sharedimages/79321db4-d86a-45df-8898-f66cc43861f5}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/8324a62cde97d7a0ebfc011068186a058324a62cde97d7a0ebfc011068186a05 => sharedimages/82b69c6b-8897-4386-be22-0d53c42ed783}/diffs.json (100%) rename test/data/registry/{images/devtable/simple/44c28f16388dcfba12cbde037563982c44c28f16388dcfba12cbde037563982c => sharedimages/83d0f1b8-5c58-4019-8bce-af257ebd0f06}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/35ccc88fa79c0d01e159fe82ed98851c35ccc88fa79c0d01e159fe82ed98851c => sharedimages/86006d61-0aa7-467d-9de9-66a35a25cb33}/diffs.json (100%) rename test/data/registry/{images/devtable/shared/4bc9d873a9b4ee89dcaaf55a55a84b974bc9d873a9b4ee89dcaaf55a55a84b97 => sharedimages/882fbbfd-623c-421b-83d3-ac0f03cab013}/diffs.json (100%) rename test/data/registry/{images/devtable/simple/d4842afed193ee9830dcc5a1e57f4fa0d4842afed193ee9830dcc5a1e57f4fa0 => sharedimages/8aa4612e-29d4-4dd6-8983-a3cb4eb6c13d}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/ff382595eafa11320e23fcb372f2f547ff382595eafa11320e23fcb372f2f547 => sharedimages/8adf6c52-50c3-4651-be96-02c966fa9949}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/4be4bd16a1fa277540b8943a58ace5e54be4bd16a1fa277540b8943a58ace5e5 => sharedimages/8be50fe6-01c7-406a-8fca-d5e208ec1270}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/85b43d0201f25007b18909d6d495f92d85b43d0201f25007b18909d6d495f92d => sharedimages/910a594e-ae04-4238-9926-607206d1ff8f}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/c1d29009854393d48c3c9a64891e2ba6c1d29009854393d48c3c9a64891e2ba6 => sharedimages/914dd053-4214-4745-ab7f-5c78cef726a9}/diffs.json (100%) rename test/data/registry/{images/devtable/shared/fc53cea92e5567da559fa149253a44ecfc53cea92e5567da559fa149253a44ec => sharedimages/938ad98e-32df-4526-ba6f-08abda5926eb}/diffs.json (100%) rename test/data/registry/{images/devtable/shared/bf3883d81e05555919f2ca9d7ca2983ebf3883d81e05555919f2ca9d7ca2983e => sharedimages/94b9ff3f-dd72-41ad-8c2e-25109787bf5d}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/c81e86f17e713dde15d87635c06ab9c5c81e86f17e713dde15d87635c06ab9c5 => sharedimages/9653fd09-98c3-46d4-9c73-99c09e7f90ae}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/e35146409ec17c0e94dbc56a120919a4e35146409ec17c0e94dbc56a120919a4 => sharedimages/9b368a3a-d147-47a0-9613-e68a90aec8c4}/diffs.json (100%) rename test/data/registry/{images/devtable/shared/74e2e6b2c6688900b1a8e31a772d217774e2e6b2c6688900b1a8e31a772d2177 => sharedimages/9de2902d-4b9e-47c6-b81e-47b434416424}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/efb34827b6c92107c252da9d451b6222efb34827b6c92107c252da9d451b6222 => sharedimages/9e8669cf-3a64-4f77-a5d2-3c4014a33675}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/6bd9f4dbacd08334ff661c9e1f1f0f3d6bd9f4dbacd08334ff661c9e1f1f0f3d => sharedimages/a1f24165-9406-47d9-bb93-20da061092ae}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/929d49280a9aab5e6aa2fe9420cc918a929d49280a9aab5e6aa2fe9420cc918a => sharedimages/a223d22e-4899-4bd7-9867-a053df90ef4a}/diffs.json (100%) rename test/data/registry/{images/devtable/simple/d2accec6b09963021245853aadfd9af8d2accec6b09963021245853aadfd9af8 => sharedimages/a5219e77-44ed-4085-8bee-e733873a3e6f}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/8de22bdae0bcfee17a4b54c46ccca70a8de22bdae0bcfee17a4b54c46ccca70a => sharedimages/a7a88216-743f-40cb-beb4-295a4dacd939}/diffs.json (100%) rename test/data/registry/{images/devtable/simple/7c66286da6034cfd15f4711f598a08c97c66286da6034cfd15f4711f598a08c9 => sharedimages/aa54a871-c433-416c-ac2d-8b2a82649ec7}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/939b37fb87a747ce351c8a1ae79b58a8939b37fb87a747ce351c8a1ae79b58a8 => sharedimages/abd60c43-3c8a-428b-87d6-a522eac6c03e}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/26762d44bb25cfe5d869f41110b96dce26762d44bb25cfe5d869f41110b96dce => sharedimages/abea3421-01a5-4979-8499-c78073d01778}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/3159d2462348da94bece4d80b4facfd93159d2462348da94bece4d80b4facfd9 => sharedimages/add92c8e-ab96-4c73-b228-463c0b3fe34a}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/5b1517bc8165d91beda306692aa867c25b1517bc8165d91beda306692aa867c2 => sharedimages/af3de1c0-3350-4ddb-97d0-e77f599410c0}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/f3decc05500979bea50ef970da1353a7f3decc05500979bea50ef970da1353a7 => sharedimages/b0de04d3-9aa1-433b-8148-60704ce9701c}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/4a0d5192dae3ab310018f57bb76f7b2d4a0d5192dae3ab310018f57bb76f7b2d => sharedimages/b1e03886-e56c-41b2-8247-bc65330f119b}/diffs.json (100%) rename test/data/registry/{images/devtable/gargantuan/fd2e6b4b1fea3d1a500a0c5745066bdffd2e6b4b1fea3d1a500a0c5745066bdf => sharedimages/b5605f56-727a-4a44-923d-abb1407e86e4}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/068bc434cfbb875d706ae4a1fab1ab1c068bc434cfbb875d706ae4a1fab1ab1c => sharedimages/b705d6fd-0f02-480b-9e4c-92073527bda1}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/7a6dcdee524b1ef0a66f5f8e3be5ae1b7a6dcdee524b1ef0a66f5f8e3be5ae1b => sharedimages/b7742b21-e1e2-4c4d-8e13-2c2acbd4ec50}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/8dbd7ccc692d6113282b0939f1798f6e8dbd7ccc692d6113282b0939f1798f6e => sharedimages/bc11c1a6-4588-479b-a336-3cf2e8b596a0}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/8eb89d1a9f0980fb348d81e7c9136a768eb89d1a9f0980fb348d81e7c9136a76 => sharedimages/bd2e01c6-b55e-48ce-abab-f86889be6351}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/ea92aa1746527ca3463d22163eba9c32ea92aa1746527ca3463d22163eba9c32 => sharedimages/bdca58b9-9123-46f2-a7af-b61d38cb31d2}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/0eaf8aa3a4640429b0a35f66ecb237d00eaf8aa3a4640429b0a35f66ecb237d0 => sharedimages/bf25cd6c-68b5-4145-bcd8-bc61b05be937}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/56f91a5d89d065364bde6c5035aaa55156f91a5d89d065364bde6c5035aaa551 => sharedimages/c1c83733-324f-43a6-93fa-1f58637a1ba2}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/01cc26e3eb8add33920614712d22382c01cc26e3eb8add33920614712d22382c => sharedimages/c29eadb1-d366-4559-b759-d44ffc0994e8}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/1c3e1a10479d118426aaa1afc2ed38261c3e1a10479d118426aaa1afc2ed3826 => sharedimages/c2cdbbca-4c1d-4596-ad9e-8ca5999643ec}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/b1663c5aba499d7b189b8b18da1e85c5b1663c5aba499d7b189b8b18da1e85c5 => sharedimages/c2d78244-02c7-4560-b5d3-45d16973dbc9}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/a764e2127e9987b40dda2cff5b68fa03a764e2127e9987b40dda2cff5b68fa03 => sharedimages/c67ca40c-1b3c-448b-82d4-52e7bd8a4da6}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/dc14642adcdd132b30870e665f13730fdc14642adcdd132b30870e665f13730f => sharedimages/ca1cf59d-68a1-4c49-87c5-73a6989b1d9d}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/34820e32c0e1bb98bf92ab69793900e834820e32c0e1bb98bf92ab69793900e8 => sharedimages/cc78948e-cf4f-4a97-aac2-0db33affd25b}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/a0d5c5f27c1c4c23a1ffebd179d3d856a0d5c5f27c1c4c23a1ffebd179d3d856 => sharedimages/cf834035-2db5-41fe-aacb-30ad533e9bf9}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/a686b51a7fd71d9a92e59ad05ab0b76da686b51a7fd71d9a92e59ad05ab0b76d => sharedimages/cfa60ed4-9ec9-4268-b283-1dbfb0f647a2}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/f967ecd286d83fa6f3e8f1908a65c6f6f967ecd286d83fa6f3e8f1908a65c6f6 => sharedimages/d3ddce06-cdb7-4acc-9afd-ea90b84fc195}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/cd292bc08dbf282f6667978704fe4fcecd292bc08dbf282f6667978704fe4fce => sharedimages/d4d29c5c-410c-4986-9dd9-6b45d513b5ef}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/ec21bac47e305066e0f2735c827cccecec21bac47e305066e0f2735c827cccec => sharedimages/d52fe920-9bd2-43f6-a1d5-7b1de9b4593b}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/aed48948f4b08def8953aa0ac4095773aed48948f4b08def8953aa0ac4095773 => sharedimages/d7f6f01c-38d0-4ef0-bde9-c969c8067a46}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/5f14df20df37b306cb8ecb423fa539c75f14df20df37b306cb8ecb423fa539c7 => sharedimages/d8c8f451-4cce-4cca-aa67-0d3ed29cb9ad}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/030581d6f421978b637479b73f862b63030581d6f421978b637479b73f862b63 => sharedimages/d95447f8-507c-453e-a7f8-3089253b53e8}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/b88a057dcc693e5a2e212e267c5f2d04b88a057dcc693e5a2e212e267c5f2d04 => sharedimages/da37b866-4262-4c68-8a42-6661880151f6}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/b74e9112918638ac9b6118ef55b0224cb74e9112918638ac9b6118ef55b0224c => sharedimages/ddb9734b-b587-4cdb-a774-da43aa2b76b8}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/d8213f593aeaefe7e14562114965dee1d8213f593aeaefe7e14562114965dee1 => sharedimages/deb73515-8ba5-4a9f-b37b-a18c6bb21a64}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/f4c4e168362552e3bef64f5e06857991f4c4e168362552e3bef64f5e06857991 => sharedimages/deed11ba-d788-4d7c-ba77-8a1f3596c3e8}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/fa95798c5aeae672bf8a68be4d954190fa95798c5aeae672bf8a68be4d954190 => sharedimages/e370876e-20fd-431c-b69e-2f187f2ddf09}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/f577c8ff27c0689c5cc58297dffdfb61f577c8ff27c0689c5cc58297dffdfb61 => sharedimages/e7a16cf3-7b8d-464b-84e8-30d39e9e3268}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/fcb18e158c1aa950a3ccf30cb668b07dfcb18e158c1aa950a3ccf30cb668b07d => sharedimages/ebe546ff-65ec-44ce-87f5-f6e07108dd22}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/fd40aaf01b09ed108501cd2df887fc07fd40aaf01b09ed108501cd2df887fc07 => sharedimages/ec100ead-dca9-443f-b588-fbc1b4cc4112}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/9646530d3f1f3b1a384947dbd5a3a0319646530d3f1f3b1a384947dbd5a3a031 => sharedimages/f0472195-49c2-408e-95c4-34625faaec23}/diffs.json (100%) rename test/data/registry/{images/devtable/superwide/d6a19d555f83b99392bdd9f44735d425d6a19d555f83b99392bdd9f44735d425 => sharedimages/f058fa2a-cba2-4308-9fb6-0c94ea8366f2}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/7eb06578cc1b5a8d0cafa075a2f634937eb06578cc1b5a8d0cafa075a2f63493 => sharedimages/f5801fc1-e889-4c2a-a194-a2b565a4d340}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/1b4bc84b74c71ac837ff19eae76e76c01b4bc84b74c71ac837ff19eae76e76c0 => sharedimages/f6834ba6-4cb9-457b-a7aa-5b93c5b30010}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/c11210080ed68235719a6f2ff39467ffc11210080ed68235719a6f2ff39467ff => sharedimages/f8337809-d8a1-47be-a14a-c705dfceaf60}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/c02f0fa3b78e16755fc38e0529571587c02f0fa3b78e16755fc38e0529571587 => sharedimages/fa7a8a7c-d895-490f-b278-f789cc9cb78d}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/7025cb49ee8cd5da3054e4b69210fdbe7025cb49ee8cd5da3054e4b69210fdbe => sharedimages/fad2bf28-105b-4a86-b8f5-ee5e3149cc01}/diffs.json (100%) rename test/data/registry/{images/public/publicrepo/cd3e411f13126e8aaf1ccd8d7e9fd28bcd3e411f13126e8aaf1ccd8d7e9fd28b => sharedimages/fca6dabc-e0a0-486a-91c7-fe55ca2f4611}/diffs.json (100%) delete mode 100644 tools/backfill_commands.py delete mode 100644 tools/backfillsizes.py diff --git a/data/database.py b/data/database.py index 0f46ff9f6..9c5f48efd 100644 --- a/data/database.py +++ b/data/database.py @@ -172,6 +172,15 @@ class EmailConfirmation(BaseModel): created = DateTimeField(default=datetime.now) +class ImageStorage(BaseModel): + uuid = CharField(default=uuid_generator) + checksum = CharField(null=True) + created = DateTimeField(null=True) + comment = TextField(null=True) + command = TextField(null=True) + image_size = BigIntegerField(null=True) + + class Image(BaseModel): # This class is intentionally denormalized. Even though images are supposed # to be globally unique we can't treat them as such for permissions and @@ -198,18 +207,6 @@ class Image(BaseModel): ) -class ImageStorage(BaseModel): - storage_uuid = CharField(default=uuid_generator) - checksum = CharField(null=True) - created = DateTimeField(null=True) - comment = TextField(null=True) - command = TextField(null=True) - image_size = BigIntegerField(null=True) - - # '/' separated list of ancestory ids, e.g. /1/2/6/7/10/ - ancestors = CharField(index=True, default='/', max_length=64535) - - class RepositoryTag(BaseModel): name = CharField() image = ForeignKeyField(Image) @@ -262,4 +259,4 @@ all_models = [User, Repository, Image, AccessToken, Role, RepositoryPermission, Visibility, RepositoryTag, EmailConfirmation, FederatedLogin, LoginService, QueueItem, RepositoryBuild, Team, TeamMember, TeamRole, Webhook, - LogEntryKind, LogEntry, PermissionPrototype] + LogEntryKind, LogEntry, PermissionPrototype, ImageStorage] diff --git a/data/model.py b/data/model.py index 524245db9..3d9c1e128 100644 --- a/data/model.py +++ b/data/model.py @@ -537,26 +537,30 @@ def get_user_teams_within_org(username, organization): def get_visible_repository_count(username=None, include_public=True, - sort=False, namespace=None): - return get_visible_repository_internal(username=username, - include_public=include_public, - sort=sort, namespace=namespace, - get_count=True) + namespace=None): + query = _visible_repository_query(username=username, + include_public=include_public, + namespace=namespace) + return query.count() + def get_visible_repositories(username=None, include_public=True, page=None, limit=None, sort=False, namespace=None): - return get_visible_repository_internal(username=username, - include_public=include_public, - page=page, limit=limit, sort=sort, - namespace=namespace, get_count=False) + query = _visible_repository_query(username=username, + include_public=include_public, page=page, + limit=limit, namespace=namespace) + + if sort: + query = query.order_by(Repository.description.desc()) + + if limit: + query = query.limit(limit) + + return query -def get_visible_repository_internal(username=None, include_public=True, - limit=None, page=None, sort=False, - namespace=None, get_count=False): - if not username and not include_public: - return [] - +def _visible_repository_query(username=None, include_public=True, limit=None, + page=None, namespace=None): query = (Repository .select() # Note: We need to leave this blank for the get_count case. Otherwise, MySQL/RDS complains. .distinct() @@ -564,8 +568,19 @@ def get_visible_repository_internal(username=None, include_public=True, .switch(Repository) .join(RepositoryPermission, JOIN_LEFT_OUTER)) + query = _filter_to_repos_for_user(query, username, namespace, include_public) + + if page: + query = query.paginate(page, limit) + elif limit: + query = query.limit(limit) + + return query + + +def _filter_to_repos_for_user(query, username=None, namespace=None, + include_public=True): where_clause = None - admin_query = None if username: UserThroughTeam = User.alias() Org = User.alias() @@ -574,6 +589,7 @@ def get_visible_repository_internal(username=None, include_public=True, AdminUser = User.alias() query = (query + .switch(RepositoryPermission) .join(User, JOIN_LEFT_OUTER) .switch(RepositoryPermission) .join(Team, JOIN_LEFT_OUTER) @@ -606,19 +622,7 @@ def get_visible_repository_internal(username=None, include_public=True, else: where_clause = new_clause - if sort: - query = query.order_by(Repository.description.desc()) - - if page: - query = query.paginate(page, limit) - elif limit: - query = query.limit(limit) - - where = query.where(where_clause) - if get_count: - return where.count() - else: - return where + return query.where(where_clause) def get_matching_repositories(repo_term, username=None): @@ -779,14 +783,13 @@ def get_repo_image(namespace_name, repository_name, image_id): .join(ImageStorage, JOIN_LEFT_OUTER) .where(Repository.name == repository_name, Repository.namespace == namespace_name, - Image.docker_image_id == image_id) - .limit(1)) - result = list(query) - if not result: + Image.docker_image_id == image_id)) + + try: + return query.get() + except Image.DoesNotExist: return None - return result[0] - def repository_is_public(namespace_name, repository_name): joined = Repository.select().join(Visibility) @@ -868,10 +871,31 @@ def create_repository(namespace, name, creating_user, visibility='private'): return repo -def create_image(docker_image_id, repository): - new_image = Image.create(docker_image_id=docker_image_id, - repository=repository) - return new_image +def create_or_link_image(docker_image_id, repository, username, create=True): + with db.transaction(): + query = (ImageStorage + .select() + .distinct() + .join(Image) + .join(Repository) + .join(Visibility) + .switch(Repository) + .join(RepositoryPermission, JOIN_LEFT_OUTER)) + + query = (_filter_to_repos_for_user(query, username) + .where(Image.docker_image_id == docker_image_id)) + + try: + storage = query.get() + msg = 'Linking image to existing storage with docker id: %s and uuid: %s' + logger.debug(msg, docker_image_id, storage.uuid) + except ImageStorage.DoesNotExist: + logger.debug('Creating new storage for docker id: %s', docker_image_id) + storage = ImageStorage.create() + + new_image = Image.create(docker_image_id=docker_image_id, + repository=repository, storage=storage) + return new_image def set_image_checksum(docker_image_id, repository, checksum): @@ -884,46 +908,67 @@ def set_image_checksum(docker_image_id, repository, checksum): def set_image_size(docker_image_id, namespace_name, repository_name, image_size): - joined = Image.select().join(Repository) - image_list = list(joined.where(Repository.name == repository_name, - Repository.namespace == namespace_name, - Image.docker_image_id == docker_image_id)) + try: + image = (Image + .select(Image, ImageStorage) + .join(Repository) + .switch(Image) + .join(ImageStorage, JOIN_LEFT_OUTER) + .where(Repository.name == repository_name, + Repository.namespace == namespace_name, + Image.docker_image_id == docker_image_id) + .get()) - if not image_list: + except Image.DoesNotExist: raise DataModelException('No image with specified id and repository') - fetched = image_list[0] - fetched.image_size = image_size - fetched.save() - return fetched + if image.storage: + image.storage.image_size = image_size + image.storage.save() + else: + image.image_size = image_size + image.save() + + return image def set_image_metadata(docker_image_id, namespace_name, repository_name, created_date_str, comment, command, parent=None): - joined = Image.select().join(Repository) - image_list = list(joined.where(Repository.name == repository_name, - Repository.namespace == namespace_name, - Image.docker_image_id == docker_image_id)) + with db.transaction(): + query = (Image + .select(Image, ImageStorage) + .join(Repository) + .switch(Image) + .join(ImageStorage) + .where(Repository.name == repository_name, + Repository.namespace == namespace_name, + Image.docker_image_id == docker_image_id)) - if not image_list: - raise DataModelException('No image with specified id and repository') + try: + fetched = query.get() + except Image.DoesNotExist: + raise DataModelException('No image with specified id and repository') - fetched = image_list[0] - fetched.created = dateutil.parser.parse(created_date_str) - fetched.comment = comment - fetched.command = command + fetched.storage.created = dateutil.parser.parse(created_date_str) + fetched.storage.comment = comment + fetched.storage.command = command - if parent: - fetched.ancestors = '%s%s/' % (parent.ancestors, parent.id) + if parent: + fetched.ancestors = '%s%s/' % (parent.ancestors, parent.id) - fetched.save() - return fetched + fetched.save() + fetched.storage.save() + return fetched def get_repository_images(namespace_name, repository_name): - joined = Image.select().join(Repository) - return joined.where(Repository.name == repository_name, - Repository.namespace == namespace_name) + return (Image + .select(Image, ImageStorage) + .join(Repository) + .switch(Image) + .join(ImageStorage, JOIN_LEFT_OUTER) + .where(Repository.name == repository_name, + Repository.namespace == namespace_name)) def list_repository_tags(namespace_name, repository_name): @@ -933,111 +978,97 @@ def list_repository_tags(namespace_name, repository_name): return with_image.where(Repository.name == repository_name, Repository.namespace == namespace_name) -def delete_tag_and_images(namespace_name, repository_name, tag_name): - all_images = get_repository_images(namespace_name, repository_name) - all_tags = list_repository_tags(namespace_name, repository_name) - - # Find the tag's information. - found_tag = None - for tag in all_tags: - if tag.name == tag_name: - found_tag = tag - break - - if not found_tag: - return - - # Build the set of database IDs corresponding to the tag's ancestor images, - # as well as the tag's image itself. - tag_image_ids = set(found_tag.image.ancestors.split('/')) - tag_image_ids.add(str(found_tag.image.id)) - - # Filter out any images that belong to any other tags. - for tag in all_tags: - if tag.name != tag_name: - # Remove all ancestors of the tag. - tag_image_ids = tag_image_ids - set(tag.image.ancestors.split('/')) - - # Remove the current image ID. - tag_image_ids.discard(str(tag.image.id)) - - # Find all the images that belong to the tag. - tag_images = [image for image in all_images - if str(image.id) in tag_image_ids] - - # Delete the tag found. - found_tag.delete_instance() - - # Delete the images found. - for image in tag_images: - image.delete_instance() - - repository_path = store.image_path(namespace_name, repository_name, - image.docker_image_id) - logger.debug('Recursively deleting image path: %s' % repository_path) - store.remove(repository_path) - def garbage_collect_repository(namespace_name, repository_name): - # Get a list of all images used by tags in the repository - tag_query = (RepositoryTag - .select(RepositoryTag, Image) - .join(Image) - .switch(RepositoryTag) - .join(Repository) - .where(Repository.name == repository_name, - Repository.namespace == namespace_name)) + with db.transaction(): + # Get a list of all images used by tags in the repository + tag_query = (RepositoryTag + .select(RepositoryTag, Image, ImageStorage) + .join(Image) + .join(ImageStorage, JOIN_LEFT_OUTER) + .switch(RepositoryTag) + .join(Repository) + .where(Repository.name == repository_name, + Repository.namespace == namespace_name)) - referenced_anscestors = set() - for tag in tag_query: - # The anscestor list is in the format '/1/2/3/', extract just the ids - anscestor_id_strings = tag.image.ancestors.split('/')[1:-1] - ancestor_list = [int(img_id_str) for img_id_str in anscestor_id_strings] - referenced_anscestors = referenced_anscestors.union(set(ancestor_list)) - referenced_anscestors.add(tag.image.id) + referenced_anscestors = set() + for tag in tag_query: + # The anscestor list is in the format '/1/2/3/', extract just the ids + anscestor_id_strings = tag.image.ancestors.split('/')[1:-1] + ancestor_list = [int(img_id_str) for img_id_str in anscestor_id_strings] + referenced_anscestors = referenced_anscestors.union(set(ancestor_list)) + referenced_anscestors.add(tag.image.id) - all_repo_images = get_repository_images(namespace_name, repository_name) - all_images = {int(img.id):img for img in all_repo_images} - to_remove = set(all_images.keys()).difference(referenced_anscestors) + all_repo_images = get_repository_images(namespace_name, repository_name) + all_images = {int(img.id): img for img in all_repo_images} + to_remove = set(all_images.keys()).difference(referenced_anscestors) - logger.info('Cleaning up unreferenced images: %s', to_remove) + logger.info('Cleaning up unreferenced images: %s', to_remove) - for image_id_to_remove in to_remove: - image_to_remove = all_images[image_id_to_remove] - image_path = store.image_path(namespace_name, repository_name, - image_to_remove.docker_image_id) - image_to_remove.delete_instance() - logger.debug('Deleting image storage: %s' % image_path) - store.remove(image_path) + uuids_to_check_for_gc = set() + for image_id_to_remove in to_remove: + image_to_remove = all_images[image_id_to_remove] + image_to_remove.delete_instance() + + if not image_to_remove.storage: + image_path = store.image_path(namespace_name, repository_name, + image_to_remove.docker_image_id, None) + logger.debug('Deleting image storage: %s', image_path) + else: + uuids_to_check_for_gc.add(image_to_remove.storage.uuid) + + storage_to_remove = (ImageStorage + .select() + .join(Image, JOIN_LEFT_OUTER) + .group_by(ImageStorage) + .where(ImageStorage.uuid << list(uuids_to_check_for_gc)) + .having(fn.Count(Image.id) == 0)) + + for storage in storage_to_remove: + logger.debug('Garbage collecting image storage: %s', storage.uuid) + storage.delete_instance() + image_path = store.image_path(namespace_name, repository_name, + image_to_remove.docker_image_id, + storage.uuid) + store.remove(image_path) return len(to_remove) def get_tag_image(namespace_name, repository_name, tag_name): - joined = Image.select().join(RepositoryTag).join(Repository) - fetched = list(joined.where(Repository.name == repository_name, - Repository.namespace == namespace_name, - RepositoryTag.name == tag_name)) + query = (Image + .select(Image, ImageStorage) + .join(RepositoryTag) + .join(Repository) + .switch(Image) + .join(ImageStorage, JOIN_LEFT_OUTER) + .where(Repository.name == repository_name, + Repository.namespace == namespace_name, + RepositoryTag.name == tag_name)) - if not fetched: + try: + return query.get() + except Image.DoesNotExist: raise DataModelException('Unable to find image for tag.') - return fetched[0] - def get_image_by_id(namespace_name, repository_name, docker_image_id): - joined = Image.select().join(Repository) - fetched = list(joined.where(Repository.name == repository_name, - Repository.namespace == namespace_name, - Image.docker_image_id == docker_image_id)) + query = (Image + .select(Image, ImageStorage) + .join(Repository) + .switch(Image) + .join(ImageStorage, JOIN_LEFT_OUTER) + .where(Repository.name == repository_name, + Repository.namespace == namespace_name, + Image.docker_image_id == docker_image_id)) - if not fetched: + try: + return query.get() + except Image.DoesNotExist: raise DataModelException('Unable to find image \'%s\' for repo \'%s/%s\'' % (docker_image_id, namespace_name, repository_name)) - return fetched[0] - def get_parent_images(image_obj): """ Returns a list of parent Image objects in chronilogical order. """ @@ -1047,8 +1078,11 @@ def get_parent_images(image_obj): if parent_db_ids == ['']: return [] - or_clauses = [(Image.id == db_id) for db_id in parent_db_ids] - parent_images = Image.select().where(reduce(operator.or_, or_clauses)) + parent_images = (Image + .select(Image, ImageStorage) + .join(ImageStorage, JOIN_LEFT_OUTER) + .where(Image.id << parent_db_ids)) + id_to_image = {unicode(image.id): image for image in parent_images} return [id_to_image[parent_id] for parent_id in parent_db_ids] @@ -1206,15 +1240,17 @@ def set_team_repo_permission(team_name, namespace_name, repository_name, def purge_repository(namespace_name, repository_name): + # Delete all tags to allow gc to reclaim storage + delete_all_repository_tags(namespace_name, repository_name) + + # Gc to remove the images and storage + garbage_collect_repository(namespace_name, repository_name) + + # Delete the rest of the repository metadata fetched = Repository.get(Repository.name == repository_name, Repository.namespace == namespace_name) fetched.delete_instance(recursive=True) - repository_path = store.repository_namespace_path(namespace_name, - repository_name) - logger.debug('Recursively deleting path: %s' % repository_path) - store.remove(repository_path) - def get_private_repo_count(username): joined = Repository.select().join(Visibility) diff --git a/endpoints/api.py b/endpoints/api.py index 4372c9774..1e694e1b0 100644 --- a/endpoints/api.py +++ b/endpoints/api.py @@ -1012,7 +1012,6 @@ def list_repos(): if include_count: repo_count = model.get_visible_repository_count(username, include_public=include_public, - sort=sort, namespace=namespace_filter) repo_query = model.get_visible_repositories(username, limit=limit, page=page, @@ -1089,14 +1088,16 @@ def delete_repository(namespace, repository): def image_view(image): + extended_props = image.storage or image + command = extended_props.command return { 'id': image.docker_image_id, - 'created': image.created, - 'comment': image.comment, - 'command': json.loads(image.command) if image.command else None, + 'created': extended_props.created, + 'comment': extended_props.comment, + 'command': json.loads(command) if command else None, 'ancestors': image.ancestors, 'dbid': image.id, - 'size': image.image_size, + 'size': extended_props.image_size, } @@ -1399,7 +1400,14 @@ def get_image(namespace, repository, image_id): def get_image_changes(namespace, repository, image_id): permission = ReadRepositoryPermission(namespace, repository) if permission.can() or model.repository_is_public(namespace, repository): - diffs_path = store.image_file_diffs_path(namespace, repository, image_id) + image = model.get_repo_image(namespace, repository, image_id) + + if not image: + abort(404) + + uuid = image.storage and image.storage.uuid + diffs_path = store.image_file_diffs_path(namespace, repository, image_id, + uuid) try: response_json = store.get_content(diffs_path) @@ -1416,7 +1424,8 @@ def get_image_changes(namespace, repository, image_id): def delete_full_tag(namespace, repository, tag): permission = AdministerRepositoryPermission(namespace, repository) if permission.can(): - model.delete_tag_and_images(namespace, repository, tag) + model.delete_tag(namespace, repository, tag) + model.garbage_collect_repository(namespace, repository) username = current_user.db_user().username log_action('delete_tag', namespace, diff --git a/endpoints/index.py b/endpoints/index.py index 5106873cb..4af671849 100644 --- a/endpoints/index.py +++ b/endpoints/index.py @@ -33,6 +33,11 @@ def generate_headers(role='read'): session['namespace'] = namespace session['repository'] = repository + if get_authenticated_user(): + session['username'] = get_authenticated_user().username + else: + session.pop('username', None) + # We run our index and registry on the same hosts for now registry_server = urlparse.urlparse(request.url).netloc response.headers['X-Docker-Endpoints'] = registry_server @@ -179,8 +184,9 @@ def create_repository(namespace, repository): if existing.docker_image_id in new_repo_images: added_images.pop(existing.docker_image_id) + username = get_authenticated_user() and get_authenticated_user().username for image_description in added_images.values(): - model.create_image(image_description['id'], repo) + model.create_or_link_image(image_description['id'], repo, username) response = make_response('Created', 201) diff --git a/endpoints/registry.py b/endpoints/registry.py index 1446238ca..9727d5ccb 100644 --- a/endpoints/registry.py +++ b/endpoints/registry.py @@ -44,8 +44,12 @@ def require_completion(f): """This make sure that the image push correctly finished.""" @wraps(f) def wrapper(namespace, repository, *args, **kwargs): - if store.exists(store.image_mark_path(namespace, repository, - kwargs['image_id'])): + image_id = kwargs['image_id'] + repo_image = model.get_repo_image(namespace, repository, image_id) + uuid = repo_image and repo_image.storage and repo_image.storage.uuid + + if store.exists(store.image_mark_path(namespace, repository, image_id, + uuid)): abort(400, 'Image %(image_id)s is being uploaded, retry later', issue='upload-in-progress', image_id=kwargs['image_id']) @@ -85,14 +89,18 @@ def set_cache_headers(f): def get_image_layer(namespace, repository, image_id, headers): permission = ReadRepositoryPermission(namespace, repository) if permission.can() or model.repository_is_public(namespace, repository): - path = store.image_layer_path(namespace, repository, image_id) + repo_image = model.get_repo_image(namespace, repository, image_id) + uuid = repo_image and repo_image.storage and repo_image.storage.uuid + + path = store.image_layer_path(namespace, repository, image_id, uuid) direct_download_url = store.get_direct_download_url(path) if direct_download_url: return redirect(direct_download_url) try: return Response(store.stream_read(path), headers=headers) except IOError: - abort(404, 'Image %(image_id)s not found', issue='unknown-image', image_id=image_id) + abort(404, 'Image %(image_id)s not found', issue='unknown-image', + image_id=image_id) abort(403) @@ -105,14 +113,17 @@ def put_image_layer(namespace, repository, image_id): if not permission.can(): abort(403) + repo_image = model.get_repo_image(namespace, repository, image_id) + uuid = repo_image and repo_image.storage and repo_image.storage.uuid try: json_data = store.get_content(store.image_json_path(namespace, repository, - image_id)) + image_id, uuid)) except IOError: - abort(404, 'Image %(image_id)s not found', issue='unknown-image', image_id=image_id) + abort(404, 'Image %(image_id)s not found', issue='unknown-image', + image_id=image_id) - layer_path = store.image_layer_path(namespace, repository, image_id) - mark_path = store.image_mark_path(namespace, repository, image_id) + layer_path = store.image_layer_path(namespace, repository, image_id, uuid) + mark_path = store.image_mark_path(namespace, repository, image_id, uuid) if store.exists(layer_path) and not store.exists(mark_path): abort(409, 'Image already exists', issue='image-exists', image_id=image_id) @@ -149,7 +160,7 @@ def put_image_layer(namespace, repository, image_id): try: checksum = store.get_content(store.image_checksum_path(namespace, repository, - image_id)) + image_id, uuid)) except IOError: # We don't have a checksum stored yet, that's fine skipping the check. # Not removing the mark though, image is not downloadable yet. @@ -193,15 +204,18 @@ def put_image_checksum(namespace, repository, image_id): abort(400, 'Checksum not found in Cookie for image %(imaage_id)s', issue='missing-checksum-cookie', image_id=image_id) - if not store.exists(store.image_json_path(namespace, repository, image_id)): + repo_image = model.get_repo_image(namespace, repository, image_id) + uuid = repo_image and repo_image.storage and repo_image.storage.uuid + if not store.exists(store.image_json_path(namespace, repository, image_id, + uuid)): abort(404, 'Image not found: %(image_id)s', issue='unknown-image', image_id=image_id) - mark_path = store.image_mark_path(namespace, repository, image_id) + mark_path = store.image_mark_path(namespace, repository, image_id, uuid) if not store.exists(mark_path): abort(409, 'Cannot set checksum for image %(image_id)s', issue='image-write-error', image_id=image_id) - err = store_checksum(namespace, repository, image_id, checksum) + err = store_checksum(namespace, repository, image_id, uuid, checksum) if err: abort(400, err) @@ -238,20 +252,24 @@ def get_image_json(namespace, repository, image_id, headers): repository): abort(403) + repo_image = model.get_repo_image(namespace, repository, image_id) + uuid = repo_image and repo_image.storage and repo_image.storage.uuid + try: data = store.get_content(store.image_json_path(namespace, repository, - image_id)) + image_id, uuid)) except IOError: flask_abort(404) try: size = store.get_size(store.image_layer_path(namespace, repository, - image_id)) + image_id, uuid)) headers['X-Docker-Size'] = str(size) except OSError: pass - checksum_path = store.image_checksum_path(namespace, repository, image_id) + checksum_path = store.image_checksum_path(namespace, repository, image_id, + uuid) if store.exists(checksum_path): headers['X-Docker-Checksum'] = store.get_content(checksum_path) @@ -271,39 +289,45 @@ def get_image_ancestry(namespace, repository, image_id, headers): repository): abort(403) + repo_image = model.get_repo_image(namespace, repository, image_id) + uuid = repo_image and repo_image.storage and repo_image.storage.uuid + try: data = store.get_content(store.image_ancestry_path(namespace, repository, - image_id)) + image_id, uuid)) except IOError: - abort(404, 'Image %(image_id)s not found', issue='unknown-image', image_id=image_id) + abort(404, 'Image %(image_id)s not found', issue='unknown-image', + image_id=image_id) response = make_response(json.dumps(json.loads(data)), 200) response.headers.extend(headers) return response -def generate_ancestry(namespace, repository, image_id, parent_id=None): +def generate_ancestry(namespace, repository, image_id, uuid, parent_id=None, + parent_uuid=None): if not parent_id: store.put_content(store.image_ancestry_path(namespace, repository, - image_id), + image_id, uuid), json.dumps([image_id])) return data = store.get_content(store.image_ancestry_path(namespace, repository, - parent_id)) + parent_id, parent_uuid)) data = json.loads(data) data.insert(0, image_id) store.put_content(store.image_ancestry_path(namespace, repository, - image_id), + image_id, uuid), json.dumps(data)) -def store_checksum(namespace, repository, image_id, checksum): +def store_checksum(namespace, repository, image_id, uuid, checksum): checksum_parts = checksum.split(':') if len(checksum_parts) != 2: return 'Invalid checksum format' # We store the checksum - checksum_path = store.image_checksum_path(namespace, repository, image_id) + checksum_path = store.image_checksum_path(namespace, repository, image_id, + uuid) store.put_content(checksum_path, checksum) @@ -327,58 +351,69 @@ def put_image_json(namespace, repository, image_id): abort(400, 'Missing key `id` in JSON for image: %(image_id)s', issue='invalid-request', image_id=image_id) + repo_image = model.get_repo_image(namespace, repository, image_id) + uuid = repo_image and repo_image.storage and repo_image.storage.uuid + # Read the checksum checksum = request.headers.get('X-Docker-Checksum') if checksum: # Storing the checksum is optional at this stage - err = store_checksum(namespace, repository, image_id, checksum) + err = store_checksum(namespace, repository, image_id, uuid, checksum) if err: abort(400, err, issue='write-error') else: # We cleanup any old checksum in case it's a retry after a fail - store.remove(store.image_checksum_path(namespace, repository, image_id)) + store.remove(store.image_checksum_path(namespace, repository, image_id, + uuid)) if image_id != data['id']: abort(400, 'JSON data contains invalid id for image: %(image_id)s', issue='invalid-request', image_id=image_id) parent_id = data.get('parent') + + parent_image = None + if parent_id: + parent_image = model.get_repo_image(namespace, repository, parent_id) + parent_uuid = (parent_image and parent_image.storage and + parent_image.storage.uuid) + if (parent_id and not - store.exists(store.image_json_path(namespace, repository, parent_id))): + store.exists(store.image_json_path(namespace, repository, parent_id, + parent_uuid))): abort(400, 'Image %(image_id)s depends on non existing parent image %(parent_id)s', issue='invalid-request', image_id=image_id, parent_id=parent_id) - json_path = store.image_json_path(namespace, repository, image_id) - mark_path = store.image_mark_path(namespace, repository, image_id) + json_path = store.image_json_path(namespace, repository, image_id, uuid) + mark_path = store.image_mark_path(namespace, repository, image_id, uuid) if store.exists(json_path) and not store.exists(mark_path): abort(409, 'Image already exists', issue='image-exists', image_id=image_id) # If we reach that point, it means that this is a new image or a retry # on a failed push # save the metadata - if parent_id: - parent_obj = model.get_image_by_id(namespace, repository, parent_id) - else: - parent_obj = None - command_list = data.get('container_config', {}).get('Cmd', None) command = json.dumps(command_list) if command_list else None model.set_image_metadata(image_id, namespace, repository, data.get('created'), data.get('comment'), command, - parent_obj) + parent_image) store.put_content(mark_path, 'true') store.put_content(json_path, request.data) - generate_ancestry(namespace, repository, image_id, parent_id) + generate_ancestry(namespace, repository, image_id, uuid, parent_id, + parent_uuid) return make_response('true', 200) def process_image_changes(namespace, repository, image_id): logger.debug('Generating diffs for image: %s' % image_id) + repo_image = model.get_repo_image(namespace, repository, image_id) + uuid = repo_image and repo_image.storage and repo_image.storage.uuid + image_diffs_path = store.image_file_diffs_path(namespace, repository, - image_id) + image_id, uuid) image_trie_path = store.image_file_trie_path(namespace, repository, - image_id) + image_id, uuid) if store.exists(image_diffs_path): logger.debug('Diffs already exist for image: %s' % image_id) @@ -400,7 +435,7 @@ def process_image_changes(namespace, repository, image_id): parent_trie.frombytes(parent_trie_bytes) # Read in the file entries from the layer tar file - layer_path = store.image_layer_path(namespace, repository, image_id) + layer_path = store.image_layer_path(namespace, repository, image_id, uuid) with store.stream_read_file(layer_path) as layer_tar_stream: removed_files = set() layer_files = changes.files_and_dirs_from_tar(layer_tar_stream, diff --git a/initdb.py b/initdb.py index cb29d5246..03cabb999 100644 --- a/initdb.py +++ b/initdb.py @@ -43,7 +43,7 @@ def __gen_image_id(repo, image_num): global_image_num = [0] -def __create_subtree(repo, structure, parent): +def __create_subtree(repo, structure, creator_username, parent): num_nodes, subtrees, last_node_tags = structure # create the nodes @@ -54,7 +54,7 @@ def __create_subtree(repo, structure, parent): logger.debug('new docker id: %s' % docker_image_id) checksum = __gen_checksum(docker_image_id) - new_image = model.create_image(docker_image_id, repo) + new_image = model.create_or_link_image(docker_image_id, repo, None) model.set_image_checksum(docker_image_id, repo, checksum) creation_time = REFERENCE_DATE + timedelta(days=image_num) @@ -69,7 +69,8 @@ def __create_subtree(repo, structure, parent): # Populate the diff file diff_path = store.image_file_diffs_path(repo.namespace, repo.name, - docker_image_id) + docker_image_id, + new_image.storage.uuid) source_diff = SAMPLE_DIFFS[image_num % len(SAMPLE_DIFFS)] with open(source_diff, 'r') as source_file: @@ -86,7 +87,7 @@ def __create_subtree(repo, structure, parent): new_image.docker_image_id) for subtree in subtrees: - __create_subtree(repo, subtree, new_image) + __create_subtree(repo, subtree, creator_username, new_image) def __generate_repository(user, name, description, is_public, permissions, @@ -106,9 +107,9 @@ def __generate_repository(user, name, description, is_public, permissions, if isinstance(structure, list): for s in structure: - __create_subtree(repo, s, None) + __create_subtree(repo, s, user.username, None) else: - __create_subtree(repo, structure, None) + __create_subtree(repo, structure, user.username, None) return repo diff --git a/storage/basestorage.py b/storage/basestorage.py index 474e53894..a89e3cb72 100644 --- a/storage/basestorage.py +++ b/storage/basestorage.py @@ -56,9 +56,6 @@ class Storage(object): base_path = self.image_path(namespace, repository, image_id, storage_uuid) return '{0}/ancestry'.format(base_path) - def repository_namespace_path(self, namespace, repository): - return '{0}/{1}/{2}/'.format(self.images, namespace, repository) - def image_file_trie_path(self, namespace, repository, image_id, storage_uuid): base_path = self.image_path(namespace, repository, image_id, storage_uuid) diff --git a/test/data/registry/images/devtable/complex/c3d710edbd3be254a2bfe7e27a7f47fdc3d710edbd3be254a2bfe7e27a7f47fd/diffs.json b/test/data/registry/sharedimages/01ca8e73-1961-40d9-bf1f-96cb90564c0b/diffs.json similarity index 100% rename from test/data/registry/images/devtable/complex/c3d710edbd3be254a2bfe7e27a7f47fdc3d710edbd3be254a2bfe7e27a7f47fd/diffs.json rename to test/data/registry/sharedimages/01ca8e73-1961-40d9-bf1f-96cb90564c0b/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/14c839f5acd4b9ed0929c60f6ad8b6ec14c839f5acd4b9ed0929c60f6ad8b6ec/diffs.json b/test/data/registry/sharedimages/0e778f76-42fb-4d77-a538-03f3a323fcd2/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/14c839f5acd4b9ed0929c60f6ad8b6ec14c839f5acd4b9ed0929c60f6ad8b6ec/diffs.json rename to test/data/registry/sharedimages/0e778f76-42fb-4d77-a538-03f3a323fcd2/diffs.json diff --git a/test/data/registry/images/devtable/complex/24aadc03801e2ca87ba34337b7df1df324aadc03801e2ca87ba34337b7df1df3/diffs.json b/test/data/registry/sharedimages/0f16ed5a-59d3-4b59-953d-c441dc6d77d2/diffs.json similarity index 100% rename from test/data/registry/images/devtable/complex/24aadc03801e2ca87ba34337b7df1df324aadc03801e2ca87ba34337b7df1df3/diffs.json rename to test/data/registry/sharedimages/0f16ed5a-59d3-4b59-953d-c441dc6d77d2/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/25f3f74ae1cdb37cd5e7fbf4b29f42d825f3f74ae1cdb37cd5e7fbf4b29f42d8/diffs.json b/test/data/registry/sharedimages/10d8eae0-28f6-45ce-b103-53cc2f59b674/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/25f3f74ae1cdb37cd5e7fbf4b29f42d825f3f74ae1cdb37cd5e7fbf4b29f42d8/diffs.json rename to test/data/registry/sharedimages/10d8eae0-28f6-45ce-b103-53cc2f59b674/diffs.json diff --git a/test/data/registry/images/devtable/complex/d3acf10ce5ad8b208ba38e626ced2946d3acf10ce5ad8b208ba38e626ced2946/diffs.json b/test/data/registry/sharedimages/1508e485-e94f-4154-87c1-53a147ff2c21/diffs.json similarity index 100% rename from test/data/registry/images/devtable/complex/d3acf10ce5ad8b208ba38e626ced2946d3acf10ce5ad8b208ba38e626ced2946/diffs.json rename to test/data/registry/sharedimages/1508e485-e94f-4154-87c1-53a147ff2c21/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/0ccb6d859cbdf08f5c71132707e144fc0ccb6d859cbdf08f5c71132707e144fc/diffs.json b/test/data/registry/sharedimages/16b2c776-20b0-426d-81c8-53abe0026706/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/0ccb6d859cbdf08f5c71132707e144fc0ccb6d859cbdf08f5c71132707e144fc/diffs.json rename to test/data/registry/sharedimages/16b2c776-20b0-426d-81c8-53abe0026706/diffs.json diff --git a/test/data/registry/images/buynlarge/orgrepo/5159d2eda87bc26f91e9b7bd0ce73f695159d2eda87bc26f91e9b7bd0ce73f69/diffs.json b/test/data/registry/sharedimages/17197704-0e3f-4829-99f2-e246787661a8/diffs.json similarity index 100% rename from test/data/registry/images/buynlarge/orgrepo/5159d2eda87bc26f91e9b7bd0ce73f695159d2eda87bc26f91e9b7bd0ce73f69/diffs.json rename to test/data/registry/sharedimages/17197704-0e3f-4829-99f2-e246787661a8/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/2561f1d3a276103635c2cde5a7dc77592561f1d3a276103635c2cde5a7dc7759/diffs.json b/test/data/registry/sharedimages/2929a979-08c3-44bf-8471-c2bda1ee55ac/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/2561f1d3a276103635c2cde5a7dc77592561f1d3a276103635c2cde5a7dc7759/diffs.json rename to test/data/registry/sharedimages/2929a979-08c3-44bf-8471-c2bda1ee55ac/diffs.json diff --git a/test/data/registry/images/devtable/complex/a4efbdc85fca8ab9db85bf6cbd54b154a4efbdc85fca8ab9db85bf6cbd54b154/diffs.json b/test/data/registry/sharedimages/2b11f03d-719c-4a5f-a8fb-f5573ecda5ca/diffs.json similarity index 100% rename from test/data/registry/images/devtable/complex/a4efbdc85fca8ab9db85bf6cbd54b154a4efbdc85fca8ab9db85bf6cbd54b154/diffs.json rename to test/data/registry/sharedimages/2b11f03d-719c-4a5f-a8fb-f5573ecda5ca/diffs.json diff --git a/test/data/registry/images/devtable/complex/5762f8352fb68b3baf43cee20946da815762f8352fb68b3baf43cee20946da81/diffs.json b/test/data/registry/sharedimages/2ddcc4ed-0a3f-400b-861c-b16f61e3d54e/diffs.json similarity index 100% rename from test/data/registry/images/devtable/complex/5762f8352fb68b3baf43cee20946da815762f8352fb68b3baf43cee20946da81/diffs.json rename to test/data/registry/sharedimages/2ddcc4ed-0a3f-400b-861c-b16f61e3d54e/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/22d54e9c626a2aa258e5185dc315d5a022d54e9c626a2aa258e5185dc315d5a0/diffs.json b/test/data/registry/sharedimages/305f4299-676e-4a2e-953a-cd299bb1a4c0/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/22d54e9c626a2aa258e5185dc315d5a022d54e9c626a2aa258e5185dc315d5a0/diffs.json rename to test/data/registry/sharedimages/305f4299-676e-4a2e-953a-cd299bb1a4c0/diffs.json diff --git a/test/data/registry/images/devtable/complex/bfbba189913c9454c3e26b62b91bb906bfbba189913c9454c3e26b62b91bb906/diffs.json b/test/data/registry/sharedimages/3408fccf-3d90-4e05-9d6e-5cbbd459330a/diffs.json similarity index 100% rename from test/data/registry/images/devtable/complex/bfbba189913c9454c3e26b62b91bb906bfbba189913c9454c3e26b62b91bb906/diffs.json rename to test/data/registry/sharedimages/3408fccf-3d90-4e05-9d6e-5cbbd459330a/diffs.json diff --git a/test/data/registry/images/buynlarge/orgrepo/0abe0a670562d152243c92280507c7e00abe0a670562d152243c92280507c7e0/diffs.json b/test/data/registry/sharedimages/353bd7fe-246a-43b5-a978-7da35c23f6ad/diffs.json similarity index 100% rename from test/data/registry/images/buynlarge/orgrepo/0abe0a670562d152243c92280507c7e00abe0a670562d152243c92280507c7e0/diffs.json rename to test/data/registry/sharedimages/353bd7fe-246a-43b5-a978-7da35c23f6ad/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/1f9c4e12e13735668f2f2b5ebed92a271f9c4e12e13735668f2f2b5ebed92a27/diffs.json b/test/data/registry/sharedimages/358d33f4-63ff-4767-95a8-3d524d685bce/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/1f9c4e12e13735668f2f2b5ebed92a271f9c4e12e13735668f2f2b5ebed92a27/diffs.json rename to test/data/registry/sharedimages/358d33f4-63ff-4767-95a8-3d524d685bce/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/425c8ea110720bca7fd14e57a59921d8425c8ea110720bca7fd14e57a59921d8/diffs.json b/test/data/registry/sharedimages/3825fa0f-5918-4da4-b56c-921f8e88d3f0/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/425c8ea110720bca7fd14e57a59921d8425c8ea110720bca7fd14e57a59921d8/diffs.json rename to test/data/registry/sharedimages/3825fa0f-5918-4da4-b56c-921f8e88d3f0/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/215cde86f7910181c2b480eddacc55f6215cde86f7910181c2b480eddacc55f6/diffs.json b/test/data/registry/sharedimages/3dc8dc91-b7c6-41d8-a74f-ab7d6d949ec0/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/215cde86f7910181c2b480eddacc55f6215cde86f7910181c2b480eddacc55f6/diffs.json rename to test/data/registry/sharedimages/3dc8dc91-b7c6-41d8-a74f-ab7d6d949ec0/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/e072d8d21d7dd0b73004258dbabc038de072d8d21d7dd0b73004258dbabc038d/diffs.json b/test/data/registry/sharedimages/3ea3578c-f04b-4804-8bbf-821c3f1d6d18/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/e072d8d21d7dd0b73004258dbabc038de072d8d21d7dd0b73004258dbabc038d/diffs.json rename to test/data/registry/sharedimages/3ea3578c-f04b-4804-8bbf-821c3f1d6d18/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/43839fc1f7d7167236871fac6b0bc26043839fc1f7d7167236871fac6b0bc260/diffs.json b/test/data/registry/sharedimages/4d2e5054-bfc3-4b4f-8135-4f03b5e69b53/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/43839fc1f7d7167236871fac6b0bc26043839fc1f7d7167236871fac6b0bc260/diffs.json rename to test/data/registry/sharedimages/4d2e5054-bfc3-4b4f-8135-4f03b5e69b53/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/b4edeedb5eb9a0322f224452b69bd545b4edeedb5eb9a0322f224452b69bd545/diffs.json b/test/data/registry/sharedimages/4de57937-8f5f-44ff-80b8-387eb4ffb469/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/b4edeedb5eb9a0322f224452b69bd545b4edeedb5eb9a0322f224452b69bd545/diffs.json rename to test/data/registry/sharedimages/4de57937-8f5f-44ff-80b8-387eb4ffb469/diffs.json diff --git a/test/data/registry/images/buynlarge/orgrepo/a99fd6afd29cd0ed2d6eb03f4ef8c3aca99fd6afd29cd0ed2d6eb03f4ef8c3ac/diffs.json b/test/data/registry/sharedimages/4f16ecc7-c2bc-427c-9894-28cb50ff04e1/diffs.json similarity index 100% rename from test/data/registry/images/buynlarge/orgrepo/a99fd6afd29cd0ed2d6eb03f4ef8c3aca99fd6afd29cd0ed2d6eb03f4ef8c3ac/diffs.json rename to test/data/registry/sharedimages/4f16ecc7-c2bc-427c-9894-28cb50ff04e1/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/1dcf485dfbdf2ee735d39f74d4ec91321dcf485dfbdf2ee735d39f74d4ec9132/diffs.json b/test/data/registry/sharedimages/5012c7dd-524a-4125-affc-c2b424a7f011/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/1dcf485dfbdf2ee735d39f74d4ec91321dcf485dfbdf2ee735d39f74d4ec9132/diffs.json rename to test/data/registry/sharedimages/5012c7dd-524a-4125-affc-c2b424a7f011/diffs.json diff --git a/test/data/registry/images/devtable/complex/333b7df80772c6336de9b3fc595649e6333b7df80772c6336de9b3fc595649e6/diffs.json b/test/data/registry/sharedimages/5072be66-6816-4f5e-a597-bd981d864768/diffs.json similarity index 100% rename from test/data/registry/images/devtable/complex/333b7df80772c6336de9b3fc595649e6333b7df80772c6336de9b3fc595649e6/diffs.json rename to test/data/registry/sharedimages/5072be66-6816-4f5e-a597-bd981d864768/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/5feb1289afba113e86027d8e1221ebd15feb1289afba113e86027d8e1221ebd1/diffs.json b/test/data/registry/sharedimages/50780ff3-75cc-4ad3-a762-5336892b1bd8/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/5feb1289afba113e86027d8e1221ebd15feb1289afba113e86027d8e1221ebd1/diffs.json rename to test/data/registry/sharedimages/50780ff3-75cc-4ad3-a762-5336892b1bd8/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/850c91f203b9eb1b83b3d2097f9a0c29850c91f203b9eb1b83b3d2097f9a0c29/diffs.json b/test/data/registry/sharedimages/51817c4b-997b-4afe-925a-99f84876e0b1/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/850c91f203b9eb1b83b3d2097f9a0c29850c91f203b9eb1b83b3d2097f9a0c29/diffs.json rename to test/data/registry/sharedimages/51817c4b-997b-4afe-925a-99f84876e0b1/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/47f6628f60a012e10865362cfaf3625a47f6628f60a012e10865362cfaf3625a/diffs.json b/test/data/registry/sharedimages/52e82877-fd84-4202-bacb-88df0e7d0da6/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/47f6628f60a012e10865362cfaf3625a47f6628f60a012e10865362cfaf3625a/diffs.json rename to test/data/registry/sharedimages/52e82877-fd84-4202-bacb-88df0e7d0da6/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/a742734a834f9049c373316825e6ab8ea742734a834f9049c373316825e6ab8e/diffs.json b/test/data/registry/sharedimages/532ac01a-d62d-4b8f-8e73-a6bee7a24455/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/a742734a834f9049c373316825e6ab8ea742734a834f9049c373316825e6ab8e/diffs.json rename to test/data/registry/sharedimages/532ac01a-d62d-4b8f-8e73-a6bee7a24455/diffs.json diff --git a/test/data/registry/images/devtable/shared/fb820a41a1b0f94cf779305c2e23d4d1fb820a41a1b0f94cf779305c2e23d4d1/diffs.json b/test/data/registry/sharedimages/53796278-cce8-4e4d-9ba3-c911f9f1fd81/diffs.json similarity index 100% rename from test/data/registry/images/devtable/shared/fb820a41a1b0f94cf779305c2e23d4d1fb820a41a1b0f94cf779305c2e23d4d1/diffs.json rename to test/data/registry/sharedimages/53796278-cce8-4e4d-9ba3-c911f9f1fd81/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/6474104fec6385f173ee7cc4346ba1716474104fec6385f173ee7cc4346ba171/diffs.json b/test/data/registry/sharedimages/5707dbfe-09e1-450b-89e5-284a96d640d1/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/6474104fec6385f173ee7cc4346ba1716474104fec6385f173ee7cc4346ba171/diffs.json rename to test/data/registry/sharedimages/5707dbfe-09e1-450b-89e5-284a96d640d1/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/5c0b2f2fede746349355d608b07904735c0b2f2fede746349355d608b0790473/diffs.json b/test/data/registry/sharedimages/57a9a644-ff7c-4578-9f1e-d39e17e86e50/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/5c0b2f2fede746349355d608b07904735c0b2f2fede746349355d608b0790473/diffs.json rename to test/data/registry/sharedimages/57a9a644-ff7c-4578-9f1e-d39e17e86e50/diffs.json diff --git a/test/data/registry/images/devtable/superwide/0e621287d1eb7c094af178a9c54ef5f10e621287d1eb7c094af178a9c54ef5f1/diffs.json b/test/data/registry/sharedimages/588a6ca4-9403-4f28-a1c2-9807c70cad7e/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/0e621287d1eb7c094af178a9c54ef5f10e621287d1eb7c094af178a9c54ef5f1/diffs.json rename to test/data/registry/sharedimages/588a6ca4-9403-4f28-a1c2-9807c70cad7e/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/b2a795ca9198e911c359f2b90e75973db2a795ca9198e911c359f2b90e75973d/diffs.json b/test/data/registry/sharedimages/59bd87db-6c0d-4fe0-b6c3-c4b5fa966c64/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/b2a795ca9198e911c359f2b90e75973db2a795ca9198e911c359f2b90e75973d/diffs.json rename to test/data/registry/sharedimages/59bd87db-6c0d-4fe0-b6c3-c4b5fa966c64/diffs.json diff --git a/test/data/registry/images/buynlarge/orgrepo/ec0dd7fc4e4c5cf34b2a24dc03ed74b9ec0dd7fc4e4c5cf34b2a24dc03ed74b9/diffs.json b/test/data/registry/sharedimages/5a380fa9-72b6-4ca4-bf12-e3ba606f439d/diffs.json similarity index 100% rename from test/data/registry/images/buynlarge/orgrepo/ec0dd7fc4e4c5cf34b2a24dc03ed74b9ec0dd7fc4e4c5cf34b2a24dc03ed74b9/diffs.json rename to test/data/registry/sharedimages/5a380fa9-72b6-4ca4-bf12-e3ba606f439d/diffs.json diff --git a/test/data/registry/images/devtable/complex/85f3f40271af0a032ec07aec57eedf9185f3f40271af0a032ec07aec57eedf91/diffs.json b/test/data/registry/sharedimages/5b07deb6-4319-437c-867f-19de0a2a789e/diffs.json similarity index 100% rename from test/data/registry/images/devtable/complex/85f3f40271af0a032ec07aec57eedf9185f3f40271af0a032ec07aec57eedf91/diffs.json rename to test/data/registry/sharedimages/5b07deb6-4319-437c-867f-19de0a2a789e/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/c9a19e9e3661af8be048a7e0fbd75ecec9a19e9e3661af8be048a7e0fbd75ece/diffs.json b/test/data/registry/sharedimages/5bb9536c-0452-46f6-9e07-b940e6438e8f/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/c9a19e9e3661af8be048a7e0fbd75ecec9a19e9e3661af8be048a7e0fbd75ece/diffs.json rename to test/data/registry/sharedimages/5bb9536c-0452-46f6-9e07-b940e6438e8f/diffs.json diff --git a/test/data/registry/images/devtable/complex/22d1aaa0bc26d6ce091069aaf97ab11d22d1aaa0bc26d6ce091069aaf97ab11d/diffs.json b/test/data/registry/sharedimages/5d130ed2-57da-464b-bd7f-6dcbbb9d21d6/diffs.json similarity index 100% rename from test/data/registry/images/devtable/complex/22d1aaa0bc26d6ce091069aaf97ab11d22d1aaa0bc26d6ce091069aaf97ab11d/diffs.json rename to test/data/registry/sharedimages/5d130ed2-57da-464b-bd7f-6dcbbb9d21d6/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/7ebb2eae1ecf7a46ef6d7401c16c6fcd7ebb2eae1ecf7a46ef6d7401c16c6fcd/diffs.json b/test/data/registry/sharedimages/5f813e36-f439-44ee-aa2f-d5171f37e9e8/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/7ebb2eae1ecf7a46ef6d7401c16c6fcd7ebb2eae1ecf7a46ef6d7401c16c6fcd/diffs.json rename to test/data/registry/sharedimages/5f813e36-f439-44ee-aa2f-d5171f37e9e8/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/aa954e497de27864883678892fe00389aa954e497de27864883678892fe00389/diffs.json b/test/data/registry/sharedimages/6165db2e-a725-4f09-83f6-ac391620c631/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/aa954e497de27864883678892fe00389aa954e497de27864883678892fe00389/diffs.json rename to test/data/registry/sharedimages/6165db2e-a725-4f09-83f6-ac391620c631/diffs.json diff --git a/test/data/registry/images/devtable/superwide/5b4f83a3bb31df974c281eaeba38d2cf5b4f83a3bb31df974c281eaeba38d2cf/diffs.json b/test/data/registry/sharedimages/6306add6-1dc3-4cdc-a11d-0ff8a57521f9/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/5b4f83a3bb31df974c281eaeba38d2cf5b4f83a3bb31df974c281eaeba38d2cf/diffs.json rename to test/data/registry/sharedimages/6306add6-1dc3-4cdc-a11d-0ff8a57521f9/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/6f07844f49df64d3f98b33c7cebc11cf6f07844f49df64d3f98b33c7cebc11cf/diffs.json b/test/data/registry/sharedimages/66dc45e9-1687-4cb6-a850-ac8c847ae547/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/6f07844f49df64d3f98b33c7cebc11cf6f07844f49df64d3f98b33c7cebc11cf/diffs.json rename to test/data/registry/sharedimages/66dc45e9-1687-4cb6-a850-ac8c847ae547/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/f52f7ded0612cff3e638da941ac53441f52f7ded0612cff3e638da941ac53441/diffs.json b/test/data/registry/sharedimages/6af86670-4135-4d3f-b96b-c80c1e3c195f/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/f52f7ded0612cff3e638da941ac53441f52f7ded0612cff3e638da941ac53441/diffs.json rename to test/data/registry/sharedimages/6af86670-4135-4d3f-b96b-c80c1e3c195f/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/c913951ea0cd4c6206f10aef139818f6c913951ea0cd4c6206f10aef139818f6/diffs.json b/test/data/registry/sharedimages/6b1c1f88-7c8b-4b01-8078-d8a11c836cd2/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/c913951ea0cd4c6206f10aef139818f6c913951ea0cd4c6206f10aef139818f6/diffs.json rename to test/data/registry/sharedimages/6b1c1f88-7c8b-4b01-8078-d8a11c836cd2/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/d935480ec258b7e5f5ff21013ee402a6d935480ec258b7e5f5ff21013ee402a6/diffs.json b/test/data/registry/sharedimages/6cd9e738-2282-4c7b-acaf-ecc1075e200d/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/d935480ec258b7e5f5ff21013ee402a6d935480ec258b7e5f5ff21013ee402a6/diffs.json rename to test/data/registry/sharedimages/6cd9e738-2282-4c7b-acaf-ecc1075e200d/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/69df2430f958b4532bca77f61438c39669df2430f958b4532bca77f61438c396/diffs.json b/test/data/registry/sharedimages/6d0ee75b-2116-45c5-acb2-a068fa5c3eaa/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/69df2430f958b4532bca77f61438c39669df2430f958b4532bca77f61438c396/diffs.json rename to test/data/registry/sharedimages/6d0ee75b-2116-45c5-acb2-a068fa5c3eaa/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/7f89233fc020acaf004fb7e4d293ae6f7f89233fc020acaf004fb7e4d293ae6f/diffs.json b/test/data/registry/sharedimages/6e0bbb9f-3d2e-460c-8560-18fdecfc02a2/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/7f89233fc020acaf004fb7e4d293ae6f7f89233fc020acaf004fb7e4d293ae6f/diffs.json rename to test/data/registry/sharedimages/6e0bbb9f-3d2e-460c-8560-18fdecfc02a2/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/ee43c0adbd6004f2fa0c91af80229849ee43c0adbd6004f2fa0c91af80229849/diffs.json b/test/data/registry/sharedimages/759c8017-ae45-4cdb-8bb1-798870dc0bfa/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/ee43c0adbd6004f2fa0c91af80229849ee43c0adbd6004f2fa0c91af80229849/diffs.json rename to test/data/registry/sharedimages/759c8017-ae45-4cdb-8bb1-798870dc0bfa/diffs.json diff --git a/test/data/registry/images/devtable/superwide/77e619ad5684dac98971aae11fb4925677e619ad5684dac98971aae11fb49256/diffs.json b/test/data/registry/sharedimages/79321db4-d86a-45df-8898-f66cc43861f5/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/77e619ad5684dac98971aae11fb4925677e619ad5684dac98971aae11fb49256/diffs.json rename to test/data/registry/sharedimages/79321db4-d86a-45df-8898-f66cc43861f5/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/8324a62cde97d7a0ebfc011068186a058324a62cde97d7a0ebfc011068186a05/diffs.json b/test/data/registry/sharedimages/82b69c6b-8897-4386-be22-0d53c42ed783/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/8324a62cde97d7a0ebfc011068186a058324a62cde97d7a0ebfc011068186a05/diffs.json rename to test/data/registry/sharedimages/82b69c6b-8897-4386-be22-0d53c42ed783/diffs.json diff --git a/test/data/registry/images/devtable/simple/44c28f16388dcfba12cbde037563982c44c28f16388dcfba12cbde037563982c/diffs.json b/test/data/registry/sharedimages/83d0f1b8-5c58-4019-8bce-af257ebd0f06/diffs.json similarity index 100% rename from test/data/registry/images/devtable/simple/44c28f16388dcfba12cbde037563982c44c28f16388dcfba12cbde037563982c/diffs.json rename to test/data/registry/sharedimages/83d0f1b8-5c58-4019-8bce-af257ebd0f06/diffs.json diff --git a/test/data/registry/images/devtable/superwide/35ccc88fa79c0d01e159fe82ed98851c35ccc88fa79c0d01e159fe82ed98851c/diffs.json b/test/data/registry/sharedimages/86006d61-0aa7-467d-9de9-66a35a25cb33/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/35ccc88fa79c0d01e159fe82ed98851c35ccc88fa79c0d01e159fe82ed98851c/diffs.json rename to test/data/registry/sharedimages/86006d61-0aa7-467d-9de9-66a35a25cb33/diffs.json diff --git a/test/data/registry/images/devtable/shared/4bc9d873a9b4ee89dcaaf55a55a84b974bc9d873a9b4ee89dcaaf55a55a84b97/diffs.json b/test/data/registry/sharedimages/882fbbfd-623c-421b-83d3-ac0f03cab013/diffs.json similarity index 100% rename from test/data/registry/images/devtable/shared/4bc9d873a9b4ee89dcaaf55a55a84b974bc9d873a9b4ee89dcaaf55a55a84b97/diffs.json rename to test/data/registry/sharedimages/882fbbfd-623c-421b-83d3-ac0f03cab013/diffs.json diff --git a/test/data/registry/images/devtable/simple/d4842afed193ee9830dcc5a1e57f4fa0d4842afed193ee9830dcc5a1e57f4fa0/diffs.json b/test/data/registry/sharedimages/8aa4612e-29d4-4dd6-8983-a3cb4eb6c13d/diffs.json similarity index 100% rename from test/data/registry/images/devtable/simple/d4842afed193ee9830dcc5a1e57f4fa0d4842afed193ee9830dcc5a1e57f4fa0/diffs.json rename to test/data/registry/sharedimages/8aa4612e-29d4-4dd6-8983-a3cb4eb6c13d/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/ff382595eafa11320e23fcb372f2f547ff382595eafa11320e23fcb372f2f547/diffs.json b/test/data/registry/sharedimages/8adf6c52-50c3-4651-be96-02c966fa9949/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/ff382595eafa11320e23fcb372f2f547ff382595eafa11320e23fcb372f2f547/diffs.json rename to test/data/registry/sharedimages/8adf6c52-50c3-4651-be96-02c966fa9949/diffs.json diff --git a/test/data/registry/images/devtable/superwide/4be4bd16a1fa277540b8943a58ace5e54be4bd16a1fa277540b8943a58ace5e5/diffs.json b/test/data/registry/sharedimages/8be50fe6-01c7-406a-8fca-d5e208ec1270/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/4be4bd16a1fa277540b8943a58ace5e54be4bd16a1fa277540b8943a58ace5e5/diffs.json rename to test/data/registry/sharedimages/8be50fe6-01c7-406a-8fca-d5e208ec1270/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/85b43d0201f25007b18909d6d495f92d85b43d0201f25007b18909d6d495f92d/diffs.json b/test/data/registry/sharedimages/910a594e-ae04-4238-9926-607206d1ff8f/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/85b43d0201f25007b18909d6d495f92d85b43d0201f25007b18909d6d495f92d/diffs.json rename to test/data/registry/sharedimages/910a594e-ae04-4238-9926-607206d1ff8f/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/c1d29009854393d48c3c9a64891e2ba6c1d29009854393d48c3c9a64891e2ba6/diffs.json b/test/data/registry/sharedimages/914dd053-4214-4745-ab7f-5c78cef726a9/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/c1d29009854393d48c3c9a64891e2ba6c1d29009854393d48c3c9a64891e2ba6/diffs.json rename to test/data/registry/sharedimages/914dd053-4214-4745-ab7f-5c78cef726a9/diffs.json diff --git a/test/data/registry/images/devtable/shared/fc53cea92e5567da559fa149253a44ecfc53cea92e5567da559fa149253a44ec/diffs.json b/test/data/registry/sharedimages/938ad98e-32df-4526-ba6f-08abda5926eb/diffs.json similarity index 100% rename from test/data/registry/images/devtable/shared/fc53cea92e5567da559fa149253a44ecfc53cea92e5567da559fa149253a44ec/diffs.json rename to test/data/registry/sharedimages/938ad98e-32df-4526-ba6f-08abda5926eb/diffs.json diff --git a/test/data/registry/images/devtable/shared/bf3883d81e05555919f2ca9d7ca2983ebf3883d81e05555919f2ca9d7ca2983e/diffs.json b/test/data/registry/sharedimages/94b9ff3f-dd72-41ad-8c2e-25109787bf5d/diffs.json similarity index 100% rename from test/data/registry/images/devtable/shared/bf3883d81e05555919f2ca9d7ca2983ebf3883d81e05555919f2ca9d7ca2983e/diffs.json rename to test/data/registry/sharedimages/94b9ff3f-dd72-41ad-8c2e-25109787bf5d/diffs.json diff --git a/test/data/registry/images/devtable/superwide/c81e86f17e713dde15d87635c06ab9c5c81e86f17e713dde15d87635c06ab9c5/diffs.json b/test/data/registry/sharedimages/9653fd09-98c3-46d4-9c73-99c09e7f90ae/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/c81e86f17e713dde15d87635c06ab9c5c81e86f17e713dde15d87635c06ab9c5/diffs.json rename to test/data/registry/sharedimages/9653fd09-98c3-46d4-9c73-99c09e7f90ae/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/e35146409ec17c0e94dbc56a120919a4e35146409ec17c0e94dbc56a120919a4/diffs.json b/test/data/registry/sharedimages/9b368a3a-d147-47a0-9613-e68a90aec8c4/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/e35146409ec17c0e94dbc56a120919a4e35146409ec17c0e94dbc56a120919a4/diffs.json rename to test/data/registry/sharedimages/9b368a3a-d147-47a0-9613-e68a90aec8c4/diffs.json diff --git a/test/data/registry/images/devtable/shared/74e2e6b2c6688900b1a8e31a772d217774e2e6b2c6688900b1a8e31a772d2177/diffs.json b/test/data/registry/sharedimages/9de2902d-4b9e-47c6-b81e-47b434416424/diffs.json similarity index 100% rename from test/data/registry/images/devtable/shared/74e2e6b2c6688900b1a8e31a772d217774e2e6b2c6688900b1a8e31a772d2177/diffs.json rename to test/data/registry/sharedimages/9de2902d-4b9e-47c6-b81e-47b434416424/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/efb34827b6c92107c252da9d451b6222efb34827b6c92107c252da9d451b6222/diffs.json b/test/data/registry/sharedimages/9e8669cf-3a64-4f77-a5d2-3c4014a33675/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/efb34827b6c92107c252da9d451b6222efb34827b6c92107c252da9d451b6222/diffs.json rename to test/data/registry/sharedimages/9e8669cf-3a64-4f77-a5d2-3c4014a33675/diffs.json diff --git a/test/data/registry/images/devtable/superwide/6bd9f4dbacd08334ff661c9e1f1f0f3d6bd9f4dbacd08334ff661c9e1f1f0f3d/diffs.json b/test/data/registry/sharedimages/a1f24165-9406-47d9-bb93-20da061092ae/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/6bd9f4dbacd08334ff661c9e1f1f0f3d6bd9f4dbacd08334ff661c9e1f1f0f3d/diffs.json rename to test/data/registry/sharedimages/a1f24165-9406-47d9-bb93-20da061092ae/diffs.json diff --git a/test/data/registry/images/devtable/superwide/929d49280a9aab5e6aa2fe9420cc918a929d49280a9aab5e6aa2fe9420cc918a/diffs.json b/test/data/registry/sharedimages/a223d22e-4899-4bd7-9867-a053df90ef4a/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/929d49280a9aab5e6aa2fe9420cc918a929d49280a9aab5e6aa2fe9420cc918a/diffs.json rename to test/data/registry/sharedimages/a223d22e-4899-4bd7-9867-a053df90ef4a/diffs.json diff --git a/test/data/registry/images/devtable/simple/d2accec6b09963021245853aadfd9af8d2accec6b09963021245853aadfd9af8/diffs.json b/test/data/registry/sharedimages/a5219e77-44ed-4085-8bee-e733873a3e6f/diffs.json similarity index 100% rename from test/data/registry/images/devtable/simple/d2accec6b09963021245853aadfd9af8d2accec6b09963021245853aadfd9af8/diffs.json rename to test/data/registry/sharedimages/a5219e77-44ed-4085-8bee-e733873a3e6f/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/8de22bdae0bcfee17a4b54c46ccca70a8de22bdae0bcfee17a4b54c46ccca70a/diffs.json b/test/data/registry/sharedimages/a7a88216-743f-40cb-beb4-295a4dacd939/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/8de22bdae0bcfee17a4b54c46ccca70a8de22bdae0bcfee17a4b54c46ccca70a/diffs.json rename to test/data/registry/sharedimages/a7a88216-743f-40cb-beb4-295a4dacd939/diffs.json diff --git a/test/data/registry/images/devtable/simple/7c66286da6034cfd15f4711f598a08c97c66286da6034cfd15f4711f598a08c9/diffs.json b/test/data/registry/sharedimages/aa54a871-c433-416c-ac2d-8b2a82649ec7/diffs.json similarity index 100% rename from test/data/registry/images/devtable/simple/7c66286da6034cfd15f4711f598a08c97c66286da6034cfd15f4711f598a08c9/diffs.json rename to test/data/registry/sharedimages/aa54a871-c433-416c-ac2d-8b2a82649ec7/diffs.json diff --git a/test/data/registry/images/devtable/superwide/939b37fb87a747ce351c8a1ae79b58a8939b37fb87a747ce351c8a1ae79b58a8/diffs.json b/test/data/registry/sharedimages/abd60c43-3c8a-428b-87d6-a522eac6c03e/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/939b37fb87a747ce351c8a1ae79b58a8939b37fb87a747ce351c8a1ae79b58a8/diffs.json rename to test/data/registry/sharedimages/abd60c43-3c8a-428b-87d6-a522eac6c03e/diffs.json diff --git a/test/data/registry/images/devtable/superwide/26762d44bb25cfe5d869f41110b96dce26762d44bb25cfe5d869f41110b96dce/diffs.json b/test/data/registry/sharedimages/abea3421-01a5-4979-8499-c78073d01778/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/26762d44bb25cfe5d869f41110b96dce26762d44bb25cfe5d869f41110b96dce/diffs.json rename to test/data/registry/sharedimages/abea3421-01a5-4979-8499-c78073d01778/diffs.json diff --git a/test/data/registry/images/devtable/superwide/3159d2462348da94bece4d80b4facfd93159d2462348da94bece4d80b4facfd9/diffs.json b/test/data/registry/sharedimages/add92c8e-ab96-4c73-b228-463c0b3fe34a/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/3159d2462348da94bece4d80b4facfd93159d2462348da94bece4d80b4facfd9/diffs.json rename to test/data/registry/sharedimages/add92c8e-ab96-4c73-b228-463c0b3fe34a/diffs.json diff --git a/test/data/registry/images/devtable/superwide/5b1517bc8165d91beda306692aa867c25b1517bc8165d91beda306692aa867c2/diffs.json b/test/data/registry/sharedimages/af3de1c0-3350-4ddb-97d0-e77f599410c0/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/5b1517bc8165d91beda306692aa867c25b1517bc8165d91beda306692aa867c2/diffs.json rename to test/data/registry/sharedimages/af3de1c0-3350-4ddb-97d0-e77f599410c0/diffs.json diff --git a/test/data/registry/images/devtable/superwide/f3decc05500979bea50ef970da1353a7f3decc05500979bea50ef970da1353a7/diffs.json b/test/data/registry/sharedimages/b0de04d3-9aa1-433b-8148-60704ce9701c/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/f3decc05500979bea50ef970da1353a7f3decc05500979bea50ef970da1353a7/diffs.json rename to test/data/registry/sharedimages/b0de04d3-9aa1-433b-8148-60704ce9701c/diffs.json diff --git a/test/data/registry/images/devtable/superwide/4a0d5192dae3ab310018f57bb76f7b2d4a0d5192dae3ab310018f57bb76f7b2d/diffs.json b/test/data/registry/sharedimages/b1e03886-e56c-41b2-8247-bc65330f119b/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/4a0d5192dae3ab310018f57bb76f7b2d4a0d5192dae3ab310018f57bb76f7b2d/diffs.json rename to test/data/registry/sharedimages/b1e03886-e56c-41b2-8247-bc65330f119b/diffs.json diff --git a/test/data/registry/images/devtable/gargantuan/fd2e6b4b1fea3d1a500a0c5745066bdffd2e6b4b1fea3d1a500a0c5745066bdf/diffs.json b/test/data/registry/sharedimages/b5605f56-727a-4a44-923d-abb1407e86e4/diffs.json similarity index 100% rename from test/data/registry/images/devtable/gargantuan/fd2e6b4b1fea3d1a500a0c5745066bdffd2e6b4b1fea3d1a500a0c5745066bdf/diffs.json rename to test/data/registry/sharedimages/b5605f56-727a-4a44-923d-abb1407e86e4/diffs.json diff --git a/test/data/registry/images/public/publicrepo/068bc434cfbb875d706ae4a1fab1ab1c068bc434cfbb875d706ae4a1fab1ab1c/diffs.json b/test/data/registry/sharedimages/b705d6fd-0f02-480b-9e4c-92073527bda1/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/068bc434cfbb875d706ae4a1fab1ab1c068bc434cfbb875d706ae4a1fab1ab1c/diffs.json rename to test/data/registry/sharedimages/b705d6fd-0f02-480b-9e4c-92073527bda1/diffs.json diff --git a/test/data/registry/images/devtable/superwide/7a6dcdee524b1ef0a66f5f8e3be5ae1b7a6dcdee524b1ef0a66f5f8e3be5ae1b/diffs.json b/test/data/registry/sharedimages/b7742b21-e1e2-4c4d-8e13-2c2acbd4ec50/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/7a6dcdee524b1ef0a66f5f8e3be5ae1b7a6dcdee524b1ef0a66f5f8e3be5ae1b/diffs.json rename to test/data/registry/sharedimages/b7742b21-e1e2-4c4d-8e13-2c2acbd4ec50/diffs.json diff --git a/test/data/registry/images/devtable/superwide/8dbd7ccc692d6113282b0939f1798f6e8dbd7ccc692d6113282b0939f1798f6e/diffs.json b/test/data/registry/sharedimages/bc11c1a6-4588-479b-a336-3cf2e8b596a0/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/8dbd7ccc692d6113282b0939f1798f6e8dbd7ccc692d6113282b0939f1798f6e/diffs.json rename to test/data/registry/sharedimages/bc11c1a6-4588-479b-a336-3cf2e8b596a0/diffs.json diff --git a/test/data/registry/images/devtable/superwide/8eb89d1a9f0980fb348d81e7c9136a768eb89d1a9f0980fb348d81e7c9136a76/diffs.json b/test/data/registry/sharedimages/bd2e01c6-b55e-48ce-abab-f86889be6351/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/8eb89d1a9f0980fb348d81e7c9136a768eb89d1a9f0980fb348d81e7c9136a76/diffs.json rename to test/data/registry/sharedimages/bd2e01c6-b55e-48ce-abab-f86889be6351/diffs.json diff --git a/test/data/registry/images/devtable/superwide/ea92aa1746527ca3463d22163eba9c32ea92aa1746527ca3463d22163eba9c32/diffs.json b/test/data/registry/sharedimages/bdca58b9-9123-46f2-a7af-b61d38cb31d2/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/ea92aa1746527ca3463d22163eba9c32ea92aa1746527ca3463d22163eba9c32/diffs.json rename to test/data/registry/sharedimages/bdca58b9-9123-46f2-a7af-b61d38cb31d2/diffs.json diff --git a/test/data/registry/images/devtable/superwide/0eaf8aa3a4640429b0a35f66ecb237d00eaf8aa3a4640429b0a35f66ecb237d0/diffs.json b/test/data/registry/sharedimages/bf25cd6c-68b5-4145-bcd8-bc61b05be937/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/0eaf8aa3a4640429b0a35f66ecb237d00eaf8aa3a4640429b0a35f66ecb237d0/diffs.json rename to test/data/registry/sharedimages/bf25cd6c-68b5-4145-bcd8-bc61b05be937/diffs.json diff --git a/test/data/registry/images/devtable/superwide/56f91a5d89d065364bde6c5035aaa55156f91a5d89d065364bde6c5035aaa551/diffs.json b/test/data/registry/sharedimages/c1c83733-324f-43a6-93fa-1f58637a1ba2/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/56f91a5d89d065364bde6c5035aaa55156f91a5d89d065364bde6c5035aaa551/diffs.json rename to test/data/registry/sharedimages/c1c83733-324f-43a6-93fa-1f58637a1ba2/diffs.json diff --git a/test/data/registry/images/devtable/superwide/01cc26e3eb8add33920614712d22382c01cc26e3eb8add33920614712d22382c/diffs.json b/test/data/registry/sharedimages/c29eadb1-d366-4559-b759-d44ffc0994e8/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/01cc26e3eb8add33920614712d22382c01cc26e3eb8add33920614712d22382c/diffs.json rename to test/data/registry/sharedimages/c29eadb1-d366-4559-b759-d44ffc0994e8/diffs.json diff --git a/test/data/registry/images/devtable/superwide/1c3e1a10479d118426aaa1afc2ed38261c3e1a10479d118426aaa1afc2ed3826/diffs.json b/test/data/registry/sharedimages/c2cdbbca-4c1d-4596-ad9e-8ca5999643ec/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/1c3e1a10479d118426aaa1afc2ed38261c3e1a10479d118426aaa1afc2ed3826/diffs.json rename to test/data/registry/sharedimages/c2cdbbca-4c1d-4596-ad9e-8ca5999643ec/diffs.json diff --git a/test/data/registry/images/devtable/superwide/b1663c5aba499d7b189b8b18da1e85c5b1663c5aba499d7b189b8b18da1e85c5/diffs.json b/test/data/registry/sharedimages/c2d78244-02c7-4560-b5d3-45d16973dbc9/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/b1663c5aba499d7b189b8b18da1e85c5b1663c5aba499d7b189b8b18da1e85c5/diffs.json rename to test/data/registry/sharedimages/c2d78244-02c7-4560-b5d3-45d16973dbc9/diffs.json diff --git a/test/data/registry/images/devtable/superwide/a764e2127e9987b40dda2cff5b68fa03a764e2127e9987b40dda2cff5b68fa03/diffs.json b/test/data/registry/sharedimages/c67ca40c-1b3c-448b-82d4-52e7bd8a4da6/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/a764e2127e9987b40dda2cff5b68fa03a764e2127e9987b40dda2cff5b68fa03/diffs.json rename to test/data/registry/sharedimages/c67ca40c-1b3c-448b-82d4-52e7bd8a4da6/diffs.json diff --git a/test/data/registry/images/devtable/superwide/dc14642adcdd132b30870e665f13730fdc14642adcdd132b30870e665f13730f/diffs.json b/test/data/registry/sharedimages/ca1cf59d-68a1-4c49-87c5-73a6989b1d9d/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/dc14642adcdd132b30870e665f13730fdc14642adcdd132b30870e665f13730f/diffs.json rename to test/data/registry/sharedimages/ca1cf59d-68a1-4c49-87c5-73a6989b1d9d/diffs.json diff --git a/test/data/registry/images/devtable/superwide/34820e32c0e1bb98bf92ab69793900e834820e32c0e1bb98bf92ab69793900e8/diffs.json b/test/data/registry/sharedimages/cc78948e-cf4f-4a97-aac2-0db33affd25b/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/34820e32c0e1bb98bf92ab69793900e834820e32c0e1bb98bf92ab69793900e8/diffs.json rename to test/data/registry/sharedimages/cc78948e-cf4f-4a97-aac2-0db33affd25b/diffs.json diff --git a/test/data/registry/images/devtable/superwide/a0d5c5f27c1c4c23a1ffebd179d3d856a0d5c5f27c1c4c23a1ffebd179d3d856/diffs.json b/test/data/registry/sharedimages/cf834035-2db5-41fe-aacb-30ad533e9bf9/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/a0d5c5f27c1c4c23a1ffebd179d3d856a0d5c5f27c1c4c23a1ffebd179d3d856/diffs.json rename to test/data/registry/sharedimages/cf834035-2db5-41fe-aacb-30ad533e9bf9/diffs.json diff --git a/test/data/registry/images/devtable/superwide/a686b51a7fd71d9a92e59ad05ab0b76da686b51a7fd71d9a92e59ad05ab0b76d/diffs.json b/test/data/registry/sharedimages/cfa60ed4-9ec9-4268-b283-1dbfb0f647a2/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/a686b51a7fd71d9a92e59ad05ab0b76da686b51a7fd71d9a92e59ad05ab0b76d/diffs.json rename to test/data/registry/sharedimages/cfa60ed4-9ec9-4268-b283-1dbfb0f647a2/diffs.json diff --git a/test/data/registry/images/devtable/superwide/f967ecd286d83fa6f3e8f1908a65c6f6f967ecd286d83fa6f3e8f1908a65c6f6/diffs.json b/test/data/registry/sharedimages/d3ddce06-cdb7-4acc-9afd-ea90b84fc195/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/f967ecd286d83fa6f3e8f1908a65c6f6f967ecd286d83fa6f3e8f1908a65c6f6/diffs.json rename to test/data/registry/sharedimages/d3ddce06-cdb7-4acc-9afd-ea90b84fc195/diffs.json diff --git a/test/data/registry/images/devtable/superwide/cd292bc08dbf282f6667978704fe4fcecd292bc08dbf282f6667978704fe4fce/diffs.json b/test/data/registry/sharedimages/d4d29c5c-410c-4986-9dd9-6b45d513b5ef/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/cd292bc08dbf282f6667978704fe4fcecd292bc08dbf282f6667978704fe4fce/diffs.json rename to test/data/registry/sharedimages/d4d29c5c-410c-4986-9dd9-6b45d513b5ef/diffs.json diff --git a/test/data/registry/images/devtable/superwide/ec21bac47e305066e0f2735c827cccecec21bac47e305066e0f2735c827cccec/diffs.json b/test/data/registry/sharedimages/d52fe920-9bd2-43f6-a1d5-7b1de9b4593b/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/ec21bac47e305066e0f2735c827cccecec21bac47e305066e0f2735c827cccec/diffs.json rename to test/data/registry/sharedimages/d52fe920-9bd2-43f6-a1d5-7b1de9b4593b/diffs.json diff --git a/test/data/registry/images/devtable/superwide/aed48948f4b08def8953aa0ac4095773aed48948f4b08def8953aa0ac4095773/diffs.json b/test/data/registry/sharedimages/d7f6f01c-38d0-4ef0-bde9-c969c8067a46/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/aed48948f4b08def8953aa0ac4095773aed48948f4b08def8953aa0ac4095773/diffs.json rename to test/data/registry/sharedimages/d7f6f01c-38d0-4ef0-bde9-c969c8067a46/diffs.json diff --git a/test/data/registry/images/public/publicrepo/5f14df20df37b306cb8ecb423fa539c75f14df20df37b306cb8ecb423fa539c7/diffs.json b/test/data/registry/sharedimages/d8c8f451-4cce-4cca-aa67-0d3ed29cb9ad/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/5f14df20df37b306cb8ecb423fa539c75f14df20df37b306cb8ecb423fa539c7/diffs.json rename to test/data/registry/sharedimages/d8c8f451-4cce-4cca-aa67-0d3ed29cb9ad/diffs.json diff --git a/test/data/registry/images/public/publicrepo/030581d6f421978b637479b73f862b63030581d6f421978b637479b73f862b63/diffs.json b/test/data/registry/sharedimages/d95447f8-507c-453e-a7f8-3089253b53e8/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/030581d6f421978b637479b73f862b63030581d6f421978b637479b73f862b63/diffs.json rename to test/data/registry/sharedimages/d95447f8-507c-453e-a7f8-3089253b53e8/diffs.json diff --git a/test/data/registry/images/devtable/superwide/b88a057dcc693e5a2e212e267c5f2d04b88a057dcc693e5a2e212e267c5f2d04/diffs.json b/test/data/registry/sharedimages/da37b866-4262-4c68-8a42-6661880151f6/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/b88a057dcc693e5a2e212e267c5f2d04b88a057dcc693e5a2e212e267c5f2d04/diffs.json rename to test/data/registry/sharedimages/da37b866-4262-4c68-8a42-6661880151f6/diffs.json diff --git a/test/data/registry/images/devtable/superwide/b74e9112918638ac9b6118ef55b0224cb74e9112918638ac9b6118ef55b0224c/diffs.json b/test/data/registry/sharedimages/ddb9734b-b587-4cdb-a774-da43aa2b76b8/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/b74e9112918638ac9b6118ef55b0224cb74e9112918638ac9b6118ef55b0224c/diffs.json rename to test/data/registry/sharedimages/ddb9734b-b587-4cdb-a774-da43aa2b76b8/diffs.json diff --git a/test/data/registry/images/devtable/superwide/d8213f593aeaefe7e14562114965dee1d8213f593aeaefe7e14562114965dee1/diffs.json b/test/data/registry/sharedimages/deb73515-8ba5-4a9f-b37b-a18c6bb21a64/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/d8213f593aeaefe7e14562114965dee1d8213f593aeaefe7e14562114965dee1/diffs.json rename to test/data/registry/sharedimages/deb73515-8ba5-4a9f-b37b-a18c6bb21a64/diffs.json diff --git a/test/data/registry/images/devtable/superwide/f4c4e168362552e3bef64f5e06857991f4c4e168362552e3bef64f5e06857991/diffs.json b/test/data/registry/sharedimages/deed11ba-d788-4d7c-ba77-8a1f3596c3e8/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/f4c4e168362552e3bef64f5e06857991f4c4e168362552e3bef64f5e06857991/diffs.json rename to test/data/registry/sharedimages/deed11ba-d788-4d7c-ba77-8a1f3596c3e8/diffs.json diff --git a/test/data/registry/images/devtable/superwide/fa95798c5aeae672bf8a68be4d954190fa95798c5aeae672bf8a68be4d954190/diffs.json b/test/data/registry/sharedimages/e370876e-20fd-431c-b69e-2f187f2ddf09/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/fa95798c5aeae672bf8a68be4d954190fa95798c5aeae672bf8a68be4d954190/diffs.json rename to test/data/registry/sharedimages/e370876e-20fd-431c-b69e-2f187f2ddf09/diffs.json diff --git a/test/data/registry/images/devtable/superwide/f577c8ff27c0689c5cc58297dffdfb61f577c8ff27c0689c5cc58297dffdfb61/diffs.json b/test/data/registry/sharedimages/e7a16cf3-7b8d-464b-84e8-30d39e9e3268/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/f577c8ff27c0689c5cc58297dffdfb61f577c8ff27c0689c5cc58297dffdfb61/diffs.json rename to test/data/registry/sharedimages/e7a16cf3-7b8d-464b-84e8-30d39e9e3268/diffs.json diff --git a/test/data/registry/images/devtable/superwide/fcb18e158c1aa950a3ccf30cb668b07dfcb18e158c1aa950a3ccf30cb668b07d/diffs.json b/test/data/registry/sharedimages/ebe546ff-65ec-44ce-87f5-f6e07108dd22/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/fcb18e158c1aa950a3ccf30cb668b07dfcb18e158c1aa950a3ccf30cb668b07d/diffs.json rename to test/data/registry/sharedimages/ebe546ff-65ec-44ce-87f5-f6e07108dd22/diffs.json diff --git a/test/data/registry/images/devtable/superwide/fd40aaf01b09ed108501cd2df887fc07fd40aaf01b09ed108501cd2df887fc07/diffs.json b/test/data/registry/sharedimages/ec100ead-dca9-443f-b588-fbc1b4cc4112/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/fd40aaf01b09ed108501cd2df887fc07fd40aaf01b09ed108501cd2df887fc07/diffs.json rename to test/data/registry/sharedimages/ec100ead-dca9-443f-b588-fbc1b4cc4112/diffs.json diff --git a/test/data/registry/images/public/publicrepo/9646530d3f1f3b1a384947dbd5a3a0319646530d3f1f3b1a384947dbd5a3a031/diffs.json b/test/data/registry/sharedimages/f0472195-49c2-408e-95c4-34625faaec23/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/9646530d3f1f3b1a384947dbd5a3a0319646530d3f1f3b1a384947dbd5a3a031/diffs.json rename to test/data/registry/sharedimages/f0472195-49c2-408e-95c4-34625faaec23/diffs.json diff --git a/test/data/registry/images/devtable/superwide/d6a19d555f83b99392bdd9f44735d425d6a19d555f83b99392bdd9f44735d425/diffs.json b/test/data/registry/sharedimages/f058fa2a-cba2-4308-9fb6-0c94ea8366f2/diffs.json similarity index 100% rename from test/data/registry/images/devtable/superwide/d6a19d555f83b99392bdd9f44735d425d6a19d555f83b99392bdd9f44735d425/diffs.json rename to test/data/registry/sharedimages/f058fa2a-cba2-4308-9fb6-0c94ea8366f2/diffs.json diff --git a/test/data/registry/images/public/publicrepo/7eb06578cc1b5a8d0cafa075a2f634937eb06578cc1b5a8d0cafa075a2f63493/diffs.json b/test/data/registry/sharedimages/f5801fc1-e889-4c2a-a194-a2b565a4d340/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/7eb06578cc1b5a8d0cafa075a2f634937eb06578cc1b5a8d0cafa075a2f63493/diffs.json rename to test/data/registry/sharedimages/f5801fc1-e889-4c2a-a194-a2b565a4d340/diffs.json diff --git a/test/data/registry/images/public/publicrepo/1b4bc84b74c71ac837ff19eae76e76c01b4bc84b74c71ac837ff19eae76e76c0/diffs.json b/test/data/registry/sharedimages/f6834ba6-4cb9-457b-a7aa-5b93c5b30010/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/1b4bc84b74c71ac837ff19eae76e76c01b4bc84b74c71ac837ff19eae76e76c0/diffs.json rename to test/data/registry/sharedimages/f6834ba6-4cb9-457b-a7aa-5b93c5b30010/diffs.json diff --git a/test/data/registry/images/public/publicrepo/c11210080ed68235719a6f2ff39467ffc11210080ed68235719a6f2ff39467ff/diffs.json b/test/data/registry/sharedimages/f8337809-d8a1-47be-a14a-c705dfceaf60/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/c11210080ed68235719a6f2ff39467ffc11210080ed68235719a6f2ff39467ff/diffs.json rename to test/data/registry/sharedimages/f8337809-d8a1-47be-a14a-c705dfceaf60/diffs.json diff --git a/test/data/registry/images/public/publicrepo/c02f0fa3b78e16755fc38e0529571587c02f0fa3b78e16755fc38e0529571587/diffs.json b/test/data/registry/sharedimages/fa7a8a7c-d895-490f-b278-f789cc9cb78d/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/c02f0fa3b78e16755fc38e0529571587c02f0fa3b78e16755fc38e0529571587/diffs.json rename to test/data/registry/sharedimages/fa7a8a7c-d895-490f-b278-f789cc9cb78d/diffs.json diff --git a/test/data/registry/images/public/publicrepo/7025cb49ee8cd5da3054e4b69210fdbe7025cb49ee8cd5da3054e4b69210fdbe/diffs.json b/test/data/registry/sharedimages/fad2bf28-105b-4a86-b8f5-ee5e3149cc01/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/7025cb49ee8cd5da3054e4b69210fdbe7025cb49ee8cd5da3054e4b69210fdbe/diffs.json rename to test/data/registry/sharedimages/fad2bf28-105b-4a86-b8f5-ee5e3149cc01/diffs.json diff --git a/test/data/registry/images/public/publicrepo/cd3e411f13126e8aaf1ccd8d7e9fd28bcd3e411f13126e8aaf1ccd8d7e9fd28b/diffs.json b/test/data/registry/sharedimages/fca6dabc-e0a0-486a-91c7-fe55ca2f4611/diffs.json similarity index 100% rename from test/data/registry/images/public/publicrepo/cd3e411f13126e8aaf1ccd8d7e9fd28bcd3e411f13126e8aaf1ccd8d7e9fd28b/diffs.json rename to test/data/registry/sharedimages/fca6dabc-e0a0-486a-91c7-fe55ca2f4611/diffs.json diff --git a/test/data/test.db b/test/data/test.db index 775f2c82df3f4c7678ad4e387d553c7218578905..f7d65a32a026d10ee18055df6e7de90bd5ab1232 100644 GIT binary patch delta 17153 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 delta 10446 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 C(B<C% diff --git a/tools/backfill_commands.py b/tools/backfill_commands.py deleted file mode 100644 index d781cdfeb..000000000 --- a/tools/backfill_commands.py +++ /dev/null @@ -1,20 +0,0 @@ -from data.database import Image -from app import app -import json - - -store = app.config['STORAGE'] - - -for image in Image.select(): - if image.command == None: - image_json_path = store.image_json_path(image.repository.namespace, - image.repository.name, - image.docker_image_id) - if store.exists(image_json_path): - data = json.loads(store.get_content(image_json_path)) - command_list = data.get('container_config', {}).get('Cmd', None) - command = json.dumps(command_list) if command_list else None - print 'Setting command to: %s' % command - image.command = command - image.save() \ No newline at end of file diff --git a/tools/backfillsizes.py b/tools/backfillsizes.py deleted file mode 100644 index 2f60cd374..000000000 --- a/tools/backfillsizes.py +++ /dev/null @@ -1,17 +0,0 @@ -from data.database import Image -from app import app - - -store = app.config['STORAGE'] - - -for image in Image.select(): - if image.image_size == None: - image_path = store.image_layer_path(image.repository.namespace, - image.repository.name, - image.docker_image_id) - if store.exists(image_path): - size = store.get_size(image_path) - print 'Setting image %s size to: %s' % (image.docker_image_id, size) - image.image_size = size - image.save() \ No newline at end of file