mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-01-11 15:32:47 +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!
|
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
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
|
## v6.0.5 - 2017-07-27
|
||||||
|
|
||||||
* Allow building the supervisor source without optimizations for easier debugging with dindctl [Pablo Carranza Velez]
|
* Allow building the supervisor source without optimizations for easier debugging with dindctl [Pablo Carranza Velez]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "resin-supervisor",
|
"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.",
|
"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",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -29,10 +29,9 @@
|
|||||||
"buffer-equal-constant-time": "^1.0.1",
|
"buffer-equal-constant-time": "^1.0.1",
|
||||||
"coffee-loader": "^0.7.3",
|
"coffee-loader": "^0.7.3",
|
||||||
"coffee-script": "~1.11.0",
|
"coffee-script": "~1.11.0",
|
||||||
"docker-delta": "1.0.3",
|
"docker-delta": "1.1.1",
|
||||||
"docker-progress": "^2.5.0",
|
"docker-progress": "^2.6.0",
|
||||||
"docker-toolbelt": "^1.3.0",
|
"docker-toolbelt": "^3.0.1",
|
||||||
"dockerode": "~2.2.9",
|
|
||||||
"event-stream": "^3.0.20",
|
"event-stream": "^3.0.20",
|
||||||
"express": "^4.0.0",
|
"express": "^4.0.0",
|
||||||
"knex": "~0.12.3",
|
"knex": "~0.12.3",
|
||||||
|
@ -156,9 +156,9 @@ application.kill = kill = (app, { updateDB = true, removeContainer = true } = {}
|
|||||||
logSystemEvent(logTypes.stopApp, app)
|
logSystemEvent(logTypes.stopApp, app)
|
||||||
device.updateState(status: 'Stopping')
|
device.updateState(status: 'Stopping')
|
||||||
container = docker.getContainer(app.containerId)
|
container = docker.getContainer(app.containerId)
|
||||||
container.stopAsync(t: 10)
|
container.stop(t: 10)
|
||||||
.then ->
|
.then ->
|
||||||
container.removeAsync(v: true) if removeContainer
|
container.remove(v: true) if removeContainer
|
||||||
return
|
return
|
||||||
# Bluebird throws OperationalError for errors resulting in the normal execution of a promisified function.
|
# Bluebird throws OperationalError for errors resulting in the normal execution of a promisified function.
|
||||||
.catch Promise.OperationalError, (err) ->
|
.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
|
# 304 means the container was already stopped - so we can just remove it
|
||||||
if statusCode is '304'
|
if statusCode is '304'
|
||||||
logSystemEvent(logTypes.stopAppNoop, app)
|
logSystemEvent(logTypes.stopAppNoop, app)
|
||||||
container.removeAsync(v: true) if removeContainer
|
container.remove(v: true) if removeContainer
|
||||||
return
|
return
|
||||||
# 404 means the container doesn't exist, precisely what we want! :D
|
# 404 means the container doesn't exist, precisely what we want! :D
|
||||||
if statusCode is '404'
|
if statusCode is '404'
|
||||||
@ -192,7 +192,7 @@ application.kill = kill = (app, { updateDB = true, removeContainer = true } = {}
|
|||||||
|
|
||||||
application.deleteImage = deleteImage = (app) ->
|
application.deleteImage = deleteImage = (app) ->
|
||||||
logSystemEvent(logTypes.deleteImageForApp, app)
|
logSystemEvent(logTypes.deleteImageForApp, app)
|
||||||
docker.getImage(app.imageId).removeAsync(force: true)
|
docker.getImage(app.imageId).remove(force: true)
|
||||||
.then ->
|
.then ->
|
||||||
logSystemEvent(logTypes.deleteImageForAppSuccess, app)
|
logSystemEvent(logTypes.deleteImageForAppSuccess, app)
|
||||||
.catch ImageNotFoundError, (err) ->
|
.catch ImageNotFoundError, (err) ->
|
||||||
@ -209,7 +209,7 @@ fetch = (app, setDeviceUpdateState = true) ->
|
|||||||
onProgress = (progress) ->
|
onProgress = (progress) ->
|
||||||
device.updateState(download_progress: progress.percentage)
|
device.updateState(download_progress: progress.percentage)
|
||||||
|
|
||||||
docker.getImage(app.imageId).inspectAsync()
|
docker.getImage(app.imageId).inspect()
|
||||||
.catch (error) ->
|
.catch (error) ->
|
||||||
device.updateState(status: 'Downloading', download_progress: 0)
|
device.updateState(status: 'Downloading', download_progress: 0)
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ fetch = (app, setDeviceUpdateState = true) ->
|
|||||||
logSystemEvent(logTypes.downloadAppSuccess, app)
|
logSystemEvent(logTypes.downloadAppSuccess, app)
|
||||||
device.updateState(status: 'Idle', download_progress: null)
|
device.updateState(status: 'Idle', download_progress: null)
|
||||||
device.setUpdateState(update_downloaded: true) if setDeviceUpdateState
|
device.setUpdateState(update_downloaded: true) if setDeviceUpdateState
|
||||||
docker.getImage(app.imageId).inspectAsync()
|
docker.getImage(app.imageId).inspect()
|
||||||
.catch (err) ->
|
.catch (err) ->
|
||||||
logSystemEvent(logTypes.downloadAppError, app, err)
|
logSystemEvent(logTypes.downloadAppError, app, err)
|
||||||
throw err
|
throw err
|
||||||
@ -268,7 +268,7 @@ application.start = start = (app) ->
|
|||||||
if app.containerId?
|
if app.containerId?
|
||||||
# If we have a container id then check it exists and if so use it.
|
# If we have a container id then check it exists and if so use it.
|
||||||
container = docker.getContainer(app.containerId)
|
container = docker.getContainer(app.containerId)
|
||||||
containerPromise = container.inspectAsync().return(container)
|
containerPromise = container.inspect().return(container)
|
||||||
else
|
else
|
||||||
containerPromise = Promise.rejected()
|
containerPromise = Promise.rejected()
|
||||||
|
|
||||||
@ -295,7 +295,7 @@ application.start = start = (app) ->
|
|||||||
shouldMountKmod(app.imageId)
|
shouldMountKmod(app.imageId)
|
||||||
.then (shouldMount) ->
|
.then (shouldMount) ->
|
||||||
binds.push('/bin/kmod:/bin/kmod:ro') if shouldMount
|
binds.push('/bin/kmod:/bin/kmod:ro') if shouldMount
|
||||||
docker.createContainerAsync(
|
docker.createContainer(
|
||||||
Image: app.imageId
|
Image: app.imageId
|
||||||
Cmd: cmd
|
Cmd: cmd
|
||||||
Tty: true
|
Tty: true
|
||||||
@ -317,7 +317,7 @@ application.start = start = (app) ->
|
|||||||
.tap (container) ->
|
.tap (container) ->
|
||||||
logSystemEvent(logTypes.startApp, app)
|
logSystemEvent(logTypes.startApp, app)
|
||||||
device.updateState(status: 'Starting')
|
device.updateState(status: 'Starting')
|
||||||
container.startAsync()
|
container.start()
|
||||||
.catch (err) ->
|
.catch (err) ->
|
||||||
statusCode = '' + err.statusCode
|
statusCode = '' + err.statusCode
|
||||||
# 304 means the container was already started, precisely what we want :)
|
# 304 means the container was already started, precisely what we want :)
|
||||||
@ -335,7 +335,7 @@ application.start = start = (app) ->
|
|||||||
throw err
|
throw err
|
||||||
.catch (err) ->
|
.catch (err) ->
|
||||||
# If starting the container failed, we remove it so that it doesn't litter
|
# If starting the container failed, we remove it so that it doesn't litter
|
||||||
container.removeAsync(v: true)
|
container.remove(v: true)
|
||||||
.then ->
|
.then ->
|
||||||
app.containerId = null
|
app.containerId = null
|
||||||
knex('app').update(app).where(appId: app.appId)
|
knex('app').update(app).where(appId: app.appId)
|
||||||
@ -827,7 +827,7 @@ application.update = update = (force, scheduled = false) ->
|
|||||||
listenToEvents = do ->
|
listenToEvents = do ->
|
||||||
appHasDied = {}
|
appHasDied = {}
|
||||||
return ->
|
return ->
|
||||||
docker.getEventsAsync()
|
docker.getEvents()
|
||||||
.then (stream) ->
|
.then (stream) ->
|
||||||
stream.on 'error', (err) ->
|
stream.on 'error', (err) ->
|
||||||
console.error('Error on docker events stream:', err, err.stack)
|
console.error('Error on docker events stream:', err, err.stack)
|
||||||
@ -870,7 +870,6 @@ application.initialize = ->
|
|||||||
|
|
||||||
module.exports = (logsChannel, offlineMode) ->
|
module.exports = (logsChannel, offlineMode) ->
|
||||||
logger.init(
|
logger.init(
|
||||||
dockerSocket: config.dockerSocket
|
|
||||||
pubnub: config.pubnub
|
pubnub: config.pubnub
|
||||||
channel: "device-#{logsChannel}-logs"
|
channel: "device-#{logsChannel}-logs"
|
||||||
offlineMode: offlineMode
|
offlineMode: offlineMode
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
config = require './config'
|
||||||
|
process.env.DOCKER_HOST ?= "unix://#{config.dockerSocket}"
|
||||||
|
|
||||||
Docker = require 'docker-toolbelt'
|
Docker = require 'docker-toolbelt'
|
||||||
{ DockerProgress } = require 'docker-progress'
|
{ DockerProgress } = require 'docker-progress'
|
||||||
Promise = require 'bluebird'
|
Promise = require 'bluebird'
|
||||||
progress = require 'request-progress'
|
progress = require 'request-progress'
|
||||||
dockerDelta = require 'docker-delta'
|
dockerDelta = require 'docker-delta'
|
||||||
config = require './config'
|
|
||||||
_ = require 'lodash'
|
_ = require 'lodash'
|
||||||
knex = require './db'
|
knex = require './db'
|
||||||
{ request } = require './request'
|
{ request } = require './request'
|
||||||
@ -11,14 +14,12 @@ Lock = require 'rwlock'
|
|||||||
utils = require './utils'
|
utils = require './utils'
|
||||||
rimraf = Promise.promisify(require('rimraf'))
|
rimraf = Promise.promisify(require('rimraf'))
|
||||||
|
|
||||||
docker = new Docker(socketPath: config.dockerSocket)
|
exports.docker = docker = new Docker()
|
||||||
|
dockerProgress = new DockerProgress(dockerToolbelt: docker)
|
||||||
exports.docker = docker
|
|
||||||
dockerProgress = new DockerProgress(socketPath: config.dockerSocket)
|
|
||||||
|
|
||||||
# Create an array of (repoTag, image_id, created) tuples like the output of `docker images`
|
# Create an array of (repoTag, image_id, created) tuples like the output of `docker images`
|
||||||
listRepoTagsAsync = ->
|
listRepoTags = ->
|
||||||
docker.listImagesAsync()
|
docker.listImages()
|
||||||
.then (images) ->
|
.then (images) ->
|
||||||
images = _.orderBy(images, 'Created', [ false ])
|
images = _.orderBy(images, 'Created', [ false ])
|
||||||
ret = []
|
ret = []
|
||||||
@ -32,7 +33,7 @@ listRepoTagsAsync = ->
|
|||||||
findSimilarImage = (repoTag) ->
|
findSimilarImage = (repoTag) ->
|
||||||
application = repoTag.split('/')[1]
|
application = repoTag.split('/')[1]
|
||||||
|
|
||||||
listRepoTagsAsync()
|
listRepoTags()
|
||||||
.then (repoTags) ->
|
.then (repoTags) ->
|
||||||
# Find the most recent image of the same application
|
# Find the most recent image of the same application
|
||||||
for repoTag in repoTags
|
for repoTag in repoTags
|
||||||
@ -46,8 +47,11 @@ findSimilarImage = (repoTag) ->
|
|||||||
getRepoAndTag = (image) ->
|
getRepoAndTag = (image) ->
|
||||||
docker.getRegistryAndName(image)
|
docker.getRegistryAndName(image)
|
||||||
.then ({ registry, imageName, tagName }) ->
|
.then ({ registry, imageName, tagName }) ->
|
||||||
registry = registry.toString().replace(':443', '')
|
if registry? and registry != 'docker.io'
|
||||||
return { repo: "#{registry}/#{imageName}", tag: tagName }
|
registry = registry.toString().replace(':443', '') + '/'
|
||||||
|
else
|
||||||
|
registry = ''
|
||||||
|
return { repo: "#{registry}#{imageName}", tag: tagName }
|
||||||
|
|
||||||
do ->
|
do ->
|
||||||
_lock = new Lock()
|
_lock = new Lock()
|
||||||
@ -116,7 +120,7 @@ do ->
|
|||||||
.then (id) ->
|
.then (id) ->
|
||||||
getRepoAndTag(imgDest)
|
getRepoAndTag(imgDest)
|
||||||
.then ({ repo, tag }) ->
|
.then ({ repo, tag }) ->
|
||||||
docker.getImage(id).tagAsync({ repo, tag, force: true })
|
docker.getImage(id).tag({ repo, tag, force: true })
|
||||||
.catch dockerDelta.OutOfSyncError, (err) ->
|
.catch dockerDelta.OutOfSyncError, (err) ->
|
||||||
console.log('Falling back to delta-from-empty')
|
console.log('Falling back to delta-from-empty')
|
||||||
exports.rsyncImageWithProgress(imgDest, { requestTimeout, totalTimeout, uuid, apiKey, startFromEmpty: true }, onProgress)
|
exports.rsyncImageWithProgress(imgDest, { requestTimeout, totalTimeout, uuid, apiKey, startFromEmpty: true }, onProgress)
|
||||||
@ -149,7 +153,7 @@ do ->
|
|||||||
.map ({ imageId }) ->
|
.map ({ imageId }) ->
|
||||||
normalizeRepoTag(imageId)
|
normalizeRepoTag(imageId)
|
||||||
supervisorTagPromise
|
supervisorTagPromise
|
||||||
docker.listImagesAsync()
|
docker.listImages()
|
||||||
.map (image) ->
|
.map (image) ->
|
||||||
image.NormalizedRepoTags = Promise.map(image.RepoTags, normalizeRepoTag)
|
image.NormalizedRepoTags = Promise.map(image.RepoTags, normalizeRepoTag)
|
||||||
Promise.props(image)
|
Promise.props(image)
|
||||||
@ -172,7 +176,7 @@ do ->
|
|||||||
)
|
)
|
||||||
.then ({ images, supervisorTags, appTags, extraTags }) ->
|
.then ({ images, supervisorTags, appTags, extraTags }) ->
|
||||||
# Cleanup containers first, so that they don't block image removal.
|
# Cleanup containers first, so that they don't block image removal.
|
||||||
docker.listContainersAsync(all: true)
|
docker.listContainers(all: true)
|
||||||
.filter (containerInfo) ->
|
.filter (containerInfo) ->
|
||||||
# Do not remove user apps.
|
# Do not remove user apps.
|
||||||
normalizeRepoTag(containerInfo.Image)
|
normalizeRepoTag(containerInfo.Image)
|
||||||
@ -185,7 +189,7 @@ do ->
|
|||||||
return true
|
return true
|
||||||
return containerHasExited(containerInfo.Id)
|
return containerHasExited(containerInfo.Id)
|
||||||
.map (containerInfo) ->
|
.map (containerInfo) ->
|
||||||
docker.getContainer(containerInfo.Id).removeAsync(v: true, force: true)
|
docker.getContainer(containerInfo.Id).remove(v: true, force: true)
|
||||||
.then ->
|
.then ->
|
||||||
console.log('Deleted container:', containerInfo.Id, containerInfo.Image)
|
console.log('Deleted container:', containerInfo.Id, containerInfo.Image)
|
||||||
.catch(_.noop)
|
.catch(_.noop)
|
||||||
@ -195,13 +199,13 @@ do ->
|
|||||||
return _.includes(appTags, tag) or _.includes(supervisorTags, tag) or _.includes(extraTags, tag)
|
return _.includes(appTags, tag) or _.includes(supervisorTags, tag) or _.includes(extraTags, tag)
|
||||||
Promise.map imagesToClean, (image) ->
|
Promise.map imagesToClean, (image) ->
|
||||||
Promise.map image.RepoTags.concat(image.Id), (tag) ->
|
Promise.map image.RepoTags.concat(image.Id), (tag) ->
|
||||||
docker.getImage(tag).removeAsync(force: true)
|
docker.getImage(tag).remove(force: true)
|
||||||
.then ->
|
.then ->
|
||||||
console.log('Deleted image:', tag, image.Id, image.RepoTags)
|
console.log('Deleted image:', tag, image.Id, image.RepoTags)
|
||||||
.catch(_.noop)
|
.catch(_.noop)
|
||||||
|
|
||||||
containerHasExited = (id) ->
|
containerHasExited = (id) ->
|
||||||
docker.getContainer(id).inspectAsync()
|
docker.getContainer(id).inspect()
|
||||||
.then (data) ->
|
.then (data) ->
|
||||||
return not data.State.Running
|
return not data.State.Running
|
||||||
|
|
||||||
@ -217,7 +221,7 @@ do ->
|
|||||||
return repoTag
|
return repoTag
|
||||||
|
|
||||||
exports.getImageEnv = (id) ->
|
exports.getImageEnv = (id) ->
|
||||||
docker.getImage(id).inspectAsync()
|
docker.getImage(id).inspect()
|
||||||
.get('Config').get('Env')
|
.get('Config').get('Env')
|
||||||
.then (env) ->
|
.then (env) ->
|
||||||
# env is an array of strings that say 'key=value'
|
# env is an array of strings that say 'key=value'
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
_ = require 'lodash'
|
_ = require 'lodash'
|
||||||
Docker = require 'dockerode'
|
Docker = require 'docker-toolbelt'
|
||||||
PUBNUB = require 'pubnub'
|
PUBNUB = require 'pubnub'
|
||||||
Promise = require 'bluebird'
|
Promise = require 'bluebird'
|
||||||
es = require 'event-stream'
|
es = require 'event-stream'
|
||||||
Lock = require 'rwlock'
|
Lock = require 'rwlock'
|
||||||
|
{ docker } = require '../docker-utils'
|
||||||
|
|
||||||
LOG_PUBLISH_INTERVAL = 110
|
LOG_PUBLISH_INTERVAL = 110
|
||||||
|
|
||||||
@ -19,13 +20,6 @@ initialised = new Promise (resolve) ->
|
|||||||
exports.init = (config) ->
|
exports.init = (config) ->
|
||||||
resolve(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.
|
# Queue up any calls to publish logs whilst we wait to be initialised.
|
||||||
publish = do ->
|
publish = do ->
|
||||||
publishQueue = [[]]
|
publishQueue = [[]]
|
||||||
@ -95,9 +89,8 @@ do ->
|
|||||||
exports.attach = (app) ->
|
exports.attach = (app) ->
|
||||||
Promise.using loggerLock(app.containerId), ->
|
Promise.using loggerLock(app.containerId), ->
|
||||||
if !attached[app.containerId]
|
if !attached[app.containerId]
|
||||||
dockerPromise.then (docker) ->
|
|
||||||
docker.getContainer(app.containerId)
|
docker.getContainer(app.containerId)
|
||||||
.logsAsync({ follow: true, stdout: true, stderr: true, timestamps: true })
|
.logs({ follow: true, stdout: true, stderr: true, timestamps: true })
|
||||||
.then (stream) ->
|
.then (stream) ->
|
||||||
attached[app.containerId] = true
|
attached[app.containerId] = true
|
||||||
stream.pipe(es.split())
|
stream.pipe(es.split())
|
||||||
|
@ -248,7 +248,7 @@ exports.fetchAndSetTargetsForDependentApps = (state, fetchFn, apiKey) ->
|
|||||||
Promise.map toBeRemoved, (app) ->
|
Promise.map toBeRemoved, (app) ->
|
||||||
fs.unlinkAsync(tarPath(app))
|
fs.unlinkAsync(tarPath(app))
|
||||||
.then ->
|
.then ->
|
||||||
docker.getImage(app.imageId).removeAsync()
|
docker.getImage(app.imageId).remove()
|
||||||
.catch (err) ->
|
.catch (err) ->
|
||||||
console.error('Could not remove image/artifacts for dependent app', err, err.stack)
|
console.error('Could not remove image/artifacts for dependent app', err, err.stack)
|
||||||
.then ->
|
.then ->
|
||||||
|
Loading…
Reference in New Issue
Block a user