Move the cleanupContainersAndImages code into the docker utils, and make use of a count of currently fetching images to only clean up images if we aren't fetching any.

This commit is contained in:
Pagan Gazzard 2014-10-17 17:35:43 +01:00 committed by Pablo Carranza Vélez
parent 07a4df1d05
commit 00d725cfac
2 changed files with 55 additions and 44 deletions

View File

@ -253,7 +253,7 @@ exports.update = update = ->
updateDeviceInfo(status: 'Cleaning old images')
# We cleanup here as we want a point when we have a consistent apps/images state, rather than potentially at a
# point where we might clean up an image we still want.
cleanupContainersAndImages()
dockerUtils.cleanupContainersAndImages()
.catch (err) ->
failedUpdates++
if currentlyUpdating is 2
@ -299,34 +299,3 @@ exports.updateDeviceInfo = updateDeviceInfo = (body) ->
.catch (error) ->
utils.mixpanelTrack('Device info update failure', {error, body})
cleanupContainersAndImages = ->
knex('app').select()
.map (app) ->
app.imageId + ':latest'
.then (apps) ->
# Make sure not to delete the supervisor image!
apps.push(config.localImage + ':latest')
apps.push(config.remoteImage + ':latest')
# Cleanup containers first, so that they don't block image removal.
docker.listContainersAsync(all: true)
.filter (containerInfo) ->
!_.contains(apps, containerInfo.Image)
.map (containerInfo) ->
docker.getContainer(containerInfo.Id).removeAsync()
.then ->
console.log('Deleted container:', containerInfo.Id, containerInfo.Image)
.catch (err) ->
console.log('Error deleting container:', containerInfo.Id, containerInfo.Image, err)
.then ->
# And then clean up the images.
docker.listImagesAsync()
.filter (image) ->
!_.any image.RepoTags, (imageId) ->
_.contains(apps, imageId)
.map (image) ->
docker.getImage(image.Id).removeAsync()
.then ->
console.log('Deleted image:', image.Id, image.RepoTags)
.catch (err) ->
console.log('Error deleting image:', image.Id, image.RepoTags, err)

View File

@ -3,6 +3,8 @@ Promise = require 'bluebird'
config = require './config'
JSONStream = require 'JSONStream'
es = require 'event-stream'
_ = require 'lodash'
knex = require './db'
docker = Promise.promisifyAll(new Docker(socketPath: config.dockerSocket))
# Hack dockerode to promisify internal classes' prototypes
@ -10,16 +12,56 @@ Promise.promisifyAll(docker.getImage().__proto__)
Promise.promisifyAll(docker.getContainer().__proto__)
exports.docker = docker
exports.fetchImage = (image) ->
docker.createImageAsync(fromImage: image)
.then (stream) ->
return new Promise (resolve, reject) ->
if stream.headers['content-type'] is 'application/json'
stream.pipe(JSONStream.parse('error'))
.pipe(es.mapSync(reject))
else
stream.pipe es.wait (error, text) ->
if error
reject(text)
stream.on('end', resolve)
do ->
# Keep track of the images being fetched, so we don't clean them up whilst fetching.
imagesBeingFetched = 0
exports.fetchImage = (image) ->
imagesBeingFetched++
docker.createImageAsync(fromImage: image)
.then (stream) ->
return new Promise (resolve, reject) ->
if stream.headers['content-type'] is 'application/json'
stream.pipe(JSONStream.parse('error'))
.pipe(es.mapSync(reject))
else
stream.pipe es.wait (error, text) ->
if error
reject(text)
stream.on('end', resolve)
.finally ->
imagesBeingFetched--
exports.cleanupContainersAndImages = ->
knex('app').select()
.map (app) ->
app.imageId + ':latest'
.then (apps) ->
# Make sure not to delete the supervisor image!
apps.push(config.localImage + ':latest')
apps.push(config.remoteImage + ':latest')
# Cleanup containers first, so that they don't block image removal.
docker.listContainersAsync(all: true)
.filter (containerInfo) ->
!_.contains(apps, containerInfo.Image)
.map (containerInfo) ->
docker.getContainer(containerInfo.Id).removeAsync()
.then ->
console.log('Deleted container:', containerInfo.Id, containerInfo.Image)
.catch (err) ->
console.log('Error deleting container:', containerInfo.Id, containerInfo.Image, err)
.then ->
# And then clean up the images, as long as we aren't currently trying to fetch any.
return if imagesBeingFetched > 0
docker.listImagesAsync()
.filter (image) ->
!_.any image.RepoTags, (imageId) ->
_.contains(apps, imageId)
.map (image) ->
docker.getImage(image.Id).removeAsync()
.then ->
console.log('Deleted image:', image.Id, image.RepoTags)
.catch (err) ->
console.log('Error deleting image:', image.Id, image.RepoTags, err)