From b9d4b8f6e8f6a08576f842fcb0b81ccc0a6d36b6 Mon Sep 17 00:00:00 2001 From: "girish@cloudron.io" Date: Thu, 21 Jan 2016 14:59:24 -0800 Subject: [PATCH] Remove docker images by tag docker pull previously used to pull down all tags. docker pull tag1 # might pull down tag2, tag3 if they are all same! docker rm tag1 # oops, tag2 and tag3 still hold on to the image However, the above feature was not possible with registry v2 (some technical stuff to do with each tag being separately signed). As a result, this feature was removed from v1 as well - https://github.com/docker/docker/pull/10571 This means we can now do: docker pull tag1 # nice docker rm tag1 # image goes away if no one else is using it references: https://github.com/docker/docker/issues/8689 https://github.com/docker/docker/pull/8193 (added this feature to v1) https://github.com/docker/docker/issues/8141 (the request) https://github.com/docker/docker/pull/10571 (removes the v1 feature) Fixes #563 --- src/docker.js | 28 ++++++++++++---------------- src/routes/test/apps-test.js | 13 +++++++------ 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/docker.js b/src/docker.js index 454cdb93f..2dc553b17 100644 --- a/src/docker.js +++ b/src/docker.js @@ -329,24 +329,20 @@ function deleteImage(manifest, callback) { var docker = exports.connection; - docker.getImage(dockerImage).inspect(function (error, result) { + var removeOptions = { + force: false, // might be shared with another instance of this app + noprune: false // delete untagged parents + }; + + // registry v1 used to pull down all *tags*. this meant that deleting image by tag was not enough (since that + // just removes the tag). we used to remove the image by id. this is not required anymore because aliases are + // not created anymore after https://github.com/docker/docker/pull/10571 + docker.getImage(dockerImage).remove(removeOptions, function (error) { if (error && error.statusCode === 404) return callback(null); + if (error && error.statusCode === 409) return callback(null); // another container using the image - if (error) return callback(error); + if (error) debug('Error removing image %s : %j', dockerImage, error); - var removeOptions = { - force: true, - noprune: false - }; - - // delete image by id because 'docker pull' pulls down all the tags and this is the only way to delete all tags - docker.getImage(result.Id).remove(removeOptions, function (error) { - if (error && error.statusCode === 404) return callback(null); - if (error && error.statusCode === 409) return callback(null); // another container using the image - - if (error) debug('Error removing image %s : %j', dockerImage, error); - - callback(error); - }); + callback(error); }); } diff --git a/src/routes/test/apps-test.js b/src/routes/test/apps-test.js index b339da305..5858cf9c1 100644 --- a/src/routes/test/apps-test.js +++ b/src/routes/test/apps-test.js @@ -42,7 +42,8 @@ var SERVER_URL = 'http://localhost:' + config.get('port'); // Test image information var TEST_IMAGE_REPO = 'cloudron/test'; var TEST_IMAGE_TAG = '10.0.0'; -var TEST_IMAGE_ID = child_process.execSync('docker inspect --format={{.Id}} ' + TEST_IMAGE_REPO + ':' + TEST_IMAGE_TAG).toString('utf8').trim(); +var TEST_IMAGE = TEST_IMAGE_REPO + ':' + TEST_IMAGE_TAG; +var TEST_IMAGE_ID = child_process.execSync('docker inspect --format={{.Id}} ' + TEST_IMAGE).toString('utf8').trim(); var APP_STORE_ID = 'test', APP_ID; var APP_LOCATION = 'appslocation'; @@ -50,10 +51,10 @@ var APP_LOCATION_2 = 'appslocationtwo'; var APP_LOCATION_NEW = 'appslocationnew'; var APP_MANIFEST = JSON.parse(fs.readFileSync(__dirname + '/../../../../test-app/CloudronManifest.json', 'utf8')); -APP_MANIFEST.dockerImage = TEST_IMAGE_REPO + ':' + TEST_IMAGE_TAG; +APP_MANIFEST.dockerImage = TEST_IMAGE; var APP_MANIFEST_1 = JSON.parse(fs.readFileSync(__dirname + '/../../../../test-app/CloudronManifest.json', 'utf8')); -APP_MANIFEST_1.dockerImage = TEST_IMAGE_REPO + ':' + TEST_IMAGE_TAG; +APP_MANIFEST_1.dockerImage = TEST_IMAGE; APP_MANIFEST_1.singleUser = true; var USERNAME = 'admin', PASSWORD = 'Foobar?1337', EMAIL ='admin@me.com'; @@ -176,7 +177,7 @@ describe('App API', function () { before(function (done) { dockerProxy = startDockerProxy(function interceptor(req, res) { - if (req.method === 'DELETE' && req.url === '/images/' + TEST_IMAGE_ID + '?force=true&noprune=false') { + if (req.method === 'DELETE' && req.url === '/images/' + TEST_IMAGE + '?force=false&noprune=false') { res.writeHead(200); res.end(); return true; @@ -573,7 +574,7 @@ describe('App installation', function () { res.writeHead(200); res.end(); return true; - } else if (req.method === 'DELETE' && req.url === '/images/' + TEST_IMAGE_ID + '?force=true&noprune=false') { + } else if (req.method === 'DELETE' && req.url === '/images/' + TEST_IMAGE + '?force=false&noprune=false') { imageDeleted = true; res.writeHead(200); res.end(); @@ -1043,7 +1044,7 @@ describe('App installation - port bindings', function () { res.writeHead(200); res.end(); return true; - } else if (req.method === 'DELETE' && req.url === '/images/' + TEST_IMAGE_ID + '?force=true&noprune=false') { + } else if (req.method === 'DELETE' && req.url === '/images/' + TEST_IMAGE + '?force=false&noprune=false') { imageDeleted = true; res.writeHead(200); res.end();