mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2024-12-23 15:32:24 +00:00
Auto-merge for PR #477 via VersionBot
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 commit is contained in:
commit
3ba7641d17
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file
|
||||
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## v6.1.0 - 2017-07-27
|
||||
|
||||
* 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 [Pablo Carranza Velez]
|
||||
|
||||
## v6.0.5 - 2017-07-27
|
||||
|
||||
* Allow building the supervisor source without optimizations for easier debugging with dindctl [Pablo Carranza Velez]
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "resin-supervisor",
|
||||
"description": "This is resin.io's Supervisor, a program that runs on IoT devices and has the task of running user Apps (which are Docker containers), and updating them as Resin's API informs it to.",
|
||||
"version": "6.0.5",
|
||||
"version": "6.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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 ->
|
||||
|
Loading…
Reference in New Issue
Block a user