From 7aedd7062dc93e5a92544bbe485e228cc732f6f6 Mon Sep 17 00:00:00 2001 From: Pablo Carranza Velez <pablo@resin.io> Date: Tue, 25 Jul 2017 17:38:42 -0300 Subject: [PATCH] Update docker-delta to 1.1.1, docker-toolbelt to 3.0.1, docker-progress to 2.6.0 to add support for deltas and overlay2 This makes the Async suffix for docker functions unnecessary. It also allows us to remove dockerode as an explicit dependency. Change-Type: minor Signed-off-by: Pablo Carranza Velez <pablo@resin.io> --- package.json | 7 +++---- src/application.coffee | 23 +++++++++++------------ src/docker-utils.coffee | 38 +++++++++++++++++++++----------------- src/lib/logger.coffee | 41 +++++++++++++++++------------------------ src/proxyvisor.coffee | 2 +- 5 files changed, 53 insertions(+), 58 deletions(-) diff --git a/package.json b/package.json index cd5dfe93..2e8ca6f8 100644 --- a/package.json +++ b/package.json @@ -29,10 +29,9 @@ "buffer-equal-constant-time": "^1.0.1", "coffee-loader": "^0.7.3", "coffee-script": "~1.11.0", - "docker-delta": "1.0.3", - "docker-progress": "^2.5.0", - "docker-toolbelt": "^1.3.0", - "dockerode": "~2.2.9", + "docker-delta": "1.1.1", + "docker-progress": "^2.6.0", + "docker-toolbelt": "^3.0.1", "event-stream": "^3.0.20", "express": "^4.0.0", "knex": "~0.12.3", diff --git a/src/application.coffee b/src/application.coffee index 74aeba08..6d77344e 100644 --- a/src/application.coffee +++ b/src/application.coffee @@ -156,9 +156,9 @@ application.kill = kill = (app, { updateDB = true, removeContainer = true } = {} logSystemEvent(logTypes.stopApp, app) device.updateState(status: 'Stopping') container = docker.getContainer(app.containerId) - container.stopAsync(t: 10) + container.stop(t: 10) .then -> - container.removeAsync(v: true) if removeContainer + container.remove(v: true) if removeContainer return # Bluebird throws OperationalError for errors resulting in the normal execution of a promisified function. .catch Promise.OperationalError, (err) -> @@ -168,7 +168,7 @@ application.kill = kill = (app, { updateDB = true, removeContainer = true } = {} # 304 means the container was already stopped - so we can just remove it if statusCode is '304' logSystemEvent(logTypes.stopAppNoop, app) - container.removeAsync(v: true) if removeContainer + container.remove(v: true) if removeContainer return # 404 means the container doesn't exist, precisely what we want! :D if statusCode is '404' @@ -192,7 +192,7 @@ application.kill = kill = (app, { updateDB = true, removeContainer = true } = {} application.deleteImage = deleteImage = (app) -> logSystemEvent(logTypes.deleteImageForApp, app) - docker.getImage(app.imageId).removeAsync(force: true) + docker.getImage(app.imageId).remove(force: true) .then -> logSystemEvent(logTypes.deleteImageForAppSuccess, app) .catch ImageNotFoundError, (err) -> @@ -209,7 +209,7 @@ fetch = (app, setDeviceUpdateState = true) -> onProgress = (progress) -> device.updateState(download_progress: progress.percentage) - docker.getImage(app.imageId).inspectAsync() + docker.getImage(app.imageId).inspect() .catch (error) -> device.updateState(status: 'Downloading', download_progress: 0) @@ -228,7 +228,7 @@ fetch = (app, setDeviceUpdateState = true) -> logSystemEvent(logTypes.downloadAppSuccess, app) device.updateState(status: 'Idle', download_progress: null) device.setUpdateState(update_downloaded: true) if setDeviceUpdateState - docker.getImage(app.imageId).inspectAsync() + docker.getImage(app.imageId).inspect() .catch (err) -> logSystemEvent(logTypes.downloadAppError, app, err) throw err @@ -268,7 +268,7 @@ application.start = start = (app) -> if app.containerId? # If we have a container id then check it exists and if so use it. container = docker.getContainer(app.containerId) - containerPromise = container.inspectAsync().return(container) + containerPromise = container.inspect().return(container) else containerPromise = Promise.rejected() @@ -295,7 +295,7 @@ application.start = start = (app) -> shouldMountKmod(app.imageId) .then (shouldMount) -> binds.push('/bin/kmod:/bin/kmod:ro') if shouldMount - docker.createContainerAsync( + docker.createContainer( Image: app.imageId Cmd: cmd Tty: true @@ -317,7 +317,7 @@ application.start = start = (app) -> .tap (container) -> logSystemEvent(logTypes.startApp, app) device.updateState(status: 'Starting') - container.startAsync() + container.start() .catch (err) -> statusCode = '' + err.statusCode # 304 means the container was already started, precisely what we want :) @@ -335,7 +335,7 @@ application.start = start = (app) -> throw err .catch (err) -> # If starting the container failed, we remove it so that it doesn't litter - container.removeAsync(v: true) + container.remove(v: true) .then -> app.containerId = null knex('app').update(app).where(appId: app.appId) @@ -827,7 +827,7 @@ application.update = update = (force, scheduled = false) -> listenToEvents = do -> appHasDied = {} return -> - docker.getEventsAsync() + docker.getEvents() .then (stream) -> stream.on 'error', (err) -> console.error('Error on docker events stream:', err, err.stack) @@ -870,7 +870,6 @@ application.initialize = -> module.exports = (logsChannel, offlineMode) -> logger.init( - dockerSocket: config.dockerSocket pubnub: config.pubnub channel: "device-#{logsChannel}-logs" offlineMode: offlineMode diff --git a/src/docker-utils.coffee b/src/docker-utils.coffee index 749736e3..938c3a91 100644 --- a/src/docker-utils.coffee +++ b/src/docker-utils.coffee @@ -1,9 +1,12 @@ +config = require './config' +process.env.DOCKER_HOST ?= "unix://#{config.dockerSocket}" + Docker = require 'docker-toolbelt' { DockerProgress } = require 'docker-progress' Promise = require 'bluebird' progress = require 'request-progress' dockerDelta = require 'docker-delta' -config = require './config' + _ = require 'lodash' knex = require './db' { request } = require './request' @@ -11,14 +14,12 @@ Lock = require 'rwlock' utils = require './utils' rimraf = Promise.promisify(require('rimraf')) -docker = new Docker(socketPath: config.dockerSocket) - -exports.docker = docker -dockerProgress = new DockerProgress(socketPath: config.dockerSocket) +exports.docker = docker = new Docker() +dockerProgress = new DockerProgress(dockerToolbelt: docker) # Create an array of (repoTag, image_id, created) tuples like the output of `docker images` -listRepoTagsAsync = -> - docker.listImagesAsync() +listRepoTags = -> + docker.listImages() .then (images) -> images = _.orderBy(images, 'Created', [ false ]) ret = [] @@ -32,7 +33,7 @@ listRepoTagsAsync = -> findSimilarImage = (repoTag) -> application = repoTag.split('/')[1] - listRepoTagsAsync() + listRepoTags() .then (repoTags) -> # Find the most recent image of the same application for repoTag in repoTags @@ -46,8 +47,11 @@ findSimilarImage = (repoTag) -> getRepoAndTag = (image) -> docker.getRegistryAndName(image) .then ({ registry, imageName, tagName }) -> - registry = registry.toString().replace(':443', '') - return { repo: "#{registry}/#{imageName}", tag: tagName } + if registry? and registry != 'docker.io' + registry = registry.toString().replace(':443', '') + '/' + else + registry = '' + return { repo: "#{registry}#{imageName}", tag: tagName } do -> _lock = new Lock() @@ -116,7 +120,7 @@ do -> .then (id) -> getRepoAndTag(imgDest) .then ({ repo, tag }) -> - docker.getImage(id).tagAsync({ repo, tag, force: true }) + docker.getImage(id).tag({ repo, tag, force: true }) .catch dockerDelta.OutOfSyncError, (err) -> console.log('Falling back to delta-from-empty') exports.rsyncImageWithProgress(imgDest, { requestTimeout, totalTimeout, uuid, apiKey, startFromEmpty: true }, onProgress) @@ -149,7 +153,7 @@ do -> .map ({ imageId }) -> normalizeRepoTag(imageId) supervisorTagPromise - docker.listImagesAsync() + docker.listImages() .map (image) -> image.NormalizedRepoTags = Promise.map(image.RepoTags, normalizeRepoTag) Promise.props(image) @@ -172,7 +176,7 @@ do -> ) .then ({ images, supervisorTags, appTags, extraTags }) -> # Cleanup containers first, so that they don't block image removal. - docker.listContainersAsync(all: true) + docker.listContainers(all: true) .filter (containerInfo) -> # Do not remove user apps. normalizeRepoTag(containerInfo.Image) @@ -185,7 +189,7 @@ do -> return true return containerHasExited(containerInfo.Id) .map (containerInfo) -> - docker.getContainer(containerInfo.Id).removeAsync(v: true, force: true) + docker.getContainer(containerInfo.Id).remove(v: true, force: true) .then -> console.log('Deleted container:', containerInfo.Id, containerInfo.Image) .catch(_.noop) @@ -195,13 +199,13 @@ do -> return _.includes(appTags, tag) or _.includes(supervisorTags, tag) or _.includes(extraTags, tag) Promise.map imagesToClean, (image) -> Promise.map image.RepoTags.concat(image.Id), (tag) -> - docker.getImage(tag).removeAsync(force: true) + docker.getImage(tag).remove(force: true) .then -> console.log('Deleted image:', tag, image.Id, image.RepoTags) .catch(_.noop) containerHasExited = (id) -> - docker.getContainer(id).inspectAsync() + docker.getContainer(id).inspect() .then (data) -> return not data.State.Running @@ -217,7 +221,7 @@ do -> return repoTag exports.getImageEnv = (id) -> - docker.getImage(id).inspectAsync() + docker.getImage(id).inspect() .get('Config').get('Env') .then (env) -> # env is an array of strings that say 'key=value' diff --git a/src/lib/logger.coffee b/src/lib/logger.coffee index ac947e59..e7e4b7cb 100644 --- a/src/lib/logger.coffee +++ b/src/lib/logger.coffee @@ -1,9 +1,10 @@ _ = require 'lodash' -Docker = require 'dockerode' +Docker = require 'docker-toolbelt' PUBNUB = require 'pubnub' Promise = require 'bluebird' es = require 'event-stream' Lock = require 'rwlock' +{ docker } = require '../docker-utils' LOG_PUBLISH_INTERVAL = 110 @@ -19,13 +20,6 @@ initialised = new Promise (resolve) -> exports.init = (config) -> resolve(config) -dockerPromise = initialised.then (config) -> - docker = Promise.promisifyAll(new Docker(socketPath: config.dockerSocket)) - # Hack dockerode to promisify internal classes' prototypes - Promise.promisifyAll(docker.getImage().constructor.prototype) - Promise.promisifyAll(docker.getContainer().constructor.prototype) - return docker - # Queue up any calls to publish logs whilst we wait to be initialised. publish = do -> publishQueue = [[]] @@ -95,19 +89,18 @@ do -> exports.attach = (app) -> Promise.using loggerLock(app.containerId), -> if !attached[app.containerId] - dockerPromise.then (docker) -> - docker.getContainer(app.containerId) - .logsAsync({ follow: true, stdout: true, stderr: true, timestamps: true }) - .then (stream) -> - attached[app.containerId] = true - stream.pipe(es.split()) - .on 'data', (logLine) -> - space = logLine.indexOf(' ') - if space > 0 - msg = { t: logLine.substr(0, space), m: logLine.substr(space + 1) } - publish(msg) - .on 'error', (err) -> - console.error('Error on container logs', err, err.stack) - attached[app.containerId] = false - .on 'end', -> - attached[app.containerId] = false + docker.getContainer(app.containerId) + .logs({ follow: true, stdout: true, stderr: true, timestamps: true }) + .then (stream) -> + attached[app.containerId] = true + stream.pipe(es.split()) + .on 'data', (logLine) -> + space = logLine.indexOf(' ') + if space > 0 + msg = { t: logLine.substr(0, space), m: logLine.substr(space + 1) } + publish(msg) + .on 'error', (err) -> + console.error('Error on container logs', err, err.stack) + attached[app.containerId] = false + .on 'end', -> + attached[app.containerId] = false diff --git a/src/proxyvisor.coffee b/src/proxyvisor.coffee index f720fdb1..19706c4b 100644 --- a/src/proxyvisor.coffee +++ b/src/proxyvisor.coffee @@ -248,7 +248,7 @@ exports.fetchAndSetTargetsForDependentApps = (state, fetchFn, apiKey) -> Promise.map toBeRemoved, (app) -> fs.unlinkAsync(tarPath(app)) .then -> - docker.getImage(app.imageId).removeAsync() + docker.getImage(app.imageId).remove() .catch (err) -> console.error('Could not remove image/artifacts for dependent app', err, err.stack) .then ->