mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-06-01 15:20:51 +00:00
Add validation for options when creating and starting containers
This commit is contained in:
parent
54288f036a
commit
e41ebbb52b
@ -8,6 +8,7 @@ fs = Promise.promisifyAll(require('fs'))
|
|||||||
mkdirp = Promise.promisify(require('mkdirp'))
|
mkdirp = Promise.promisify(require('mkdirp'))
|
||||||
path = require 'path'
|
path = require 'path'
|
||||||
utils = require './utils'
|
utils = require './utils'
|
||||||
|
config = require './config'
|
||||||
|
|
||||||
composePathSrc = (appId) ->
|
composePathSrc = (appId) ->
|
||||||
return "/mnt/root#{config.dataPath}/#{appId}/docker-compose.yml"
|
return "/mnt/root#{config.dataPath}/#{appId}/docker-compose.yml"
|
||||||
@ -39,12 +40,6 @@ writeComposeFile = (composeSpec, dstPath) ->
|
|||||||
.then ->
|
.then ->
|
||||||
execAsync('sync')
|
execAsync('sync')
|
||||||
|
|
||||||
validateServiceOptions = (service) ->
|
|
||||||
Promise.try ->
|
|
||||||
options = _.keys(service)
|
|
||||||
_.each options, (option) ->
|
|
||||||
throw new Error("Using #{option} is not allowed.") if !_.includes(utils.validComposeOptions, option)
|
|
||||||
|
|
||||||
# Runs docker-compose up using the compose YAML at "path".
|
# Runs docker-compose up using the compose YAML at "path".
|
||||||
# Reports status and errors in JSON to the onStatus function.
|
# Reports status and errors in JSON to the onStatus function.
|
||||||
# Copies the compose file from srcPath to dstPath adding default volumes
|
# Copies the compose file from srcPath to dstPath adding default volumes
|
||||||
@ -68,11 +63,11 @@ exports.up = (appId, onStatus) ->
|
|||||||
.catch ->
|
.catch ->
|
||||||
dockerUtils.pullAndProtectImage(service.image, reportStatus)
|
dockerUtils.pullAndProtectImage(service.image, reportStatus)
|
||||||
.then ->
|
.then ->
|
||||||
validateServiceOptions(service)
|
utils.validateKeys(service, utils.validComposeOptions)
|
||||||
.then ->
|
.then ->
|
||||||
services[serviceName].volumes = utils.defaultBinds(composeDataPath(appId, serviceName))
|
services[serviceName].volumes = utils.defaultBinds(composeDataPath(appId, serviceName))
|
||||||
.then ->
|
.then ->
|
||||||
writeComposeFile(composeSpec, dstPath)
|
writeComposeFile(composeSpec, composePathDst(appId))
|
||||||
.then ->
|
.then ->
|
||||||
runComposeCommand(['up', '-d'], appId, reportStatus)
|
runComposeCommand(['up', '-d'], appId, reportStatus)
|
||||||
.catch (err) ->
|
.catch (err) ->
|
||||||
@ -82,7 +77,7 @@ exports.up = (appId, onStatus) ->
|
|||||||
|
|
||||||
# Runs docker-compose down using the compose YAML at "path".
|
# Runs docker-compose down using the compose YAML at "path".
|
||||||
# Reports status and errors in JSON to the onStatus function.
|
# Reports status and errors in JSON to the onStatus function.
|
||||||
exports.down = (appId, onStatus)
|
exports.down = (appId, onStatus) ->
|
||||||
onStatus ?= console.log.bind(console)
|
onStatus ?= console.log.bind(console)
|
||||||
reportStatus = (status) ->
|
reportStatus = (status) ->
|
||||||
try onStatus(status)
|
try onStatus(status)
|
||||||
|
@ -8,6 +8,7 @@ _ = require 'lodash'
|
|||||||
knex = require './db'
|
knex = require './db'
|
||||||
{ request } = require './request'
|
{ request } = require './request'
|
||||||
Lock = require 'rwlock'
|
Lock = require 'rwlock'
|
||||||
|
utils = require './utils'
|
||||||
|
|
||||||
docker = new Docker(socketPath: config.dockerSocket)
|
docker = new Docker(socketPath: config.dockerSocket)
|
||||||
|
|
||||||
@ -270,7 +271,11 @@ do ->
|
|||||||
404: 'no such container'
|
404: 'no such container'
|
||||||
406: 'impossible to attach'
|
406: 'impossible to attach'
|
||||||
500: 'server error'
|
500: 'server error'
|
||||||
docker.modem.dialAsync(optsf)
|
utils.validateKeys(options, utils.validContainerOptions)
|
||||||
|
.then ->
|
||||||
|
utils.validateKeys(options.HostConfig, utils.validHostConfigOptions)
|
||||||
|
.then ->
|
||||||
|
docker.modem.dialAsync(optsf)
|
||||||
.then (data) ->
|
.then (data) ->
|
||||||
containerId = data.Id
|
containerId = data.Id
|
||||||
trx('container').update({ containerId }).where({ id })
|
trx('container').update({ containerId }).where({ id })
|
||||||
@ -284,7 +289,9 @@ do ->
|
|||||||
res.status(500).send(err?.message or err or 'Unknown error')
|
res.status(500).send(err?.message or err or 'Unknown error')
|
||||||
|
|
||||||
startContainer = (containerId, options) ->
|
startContainer = (containerId, options) ->
|
||||||
docker.getContainer(containerId).startAsync(options)
|
utils.validateKeys(options, utils.validHostConfigOptions)
|
||||||
|
.then ->
|
||||||
|
docker.getContainer(containerId).startAsync(options)
|
||||||
exports.startContainer = (req, res) ->
|
exports.startContainer = (req, res) ->
|
||||||
startContainer(req.params.id, req.body)
|
startContainer(req.params.id, req.body)
|
||||||
.then (data) ->
|
.then (data) ->
|
||||||
@ -342,7 +349,7 @@ do ->
|
|||||||
deleteContainer(oldContainerId, v: true)
|
deleteContainer(oldContainerId, v: true)
|
||||||
.then ->
|
.then ->
|
||||||
createContainer(req.body, oldContainer.id)
|
createContainer(req.body, oldContainer.id)
|
||||||
.then ->
|
.then (data) ->
|
||||||
startContainer(data.Id)
|
startContainer(data.Id)
|
||||||
.then (data) ->
|
.then (data) ->
|
||||||
res.json(data)
|
res.json(data)
|
||||||
|
@ -267,3 +267,71 @@ exports.validComposeOptions = [
|
|||||||
'networks'
|
'networks'
|
||||||
'pid'
|
'pid'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
exports.validContainerOptions = [
|
||||||
|
'Hostname'
|
||||||
|
'Domainname'
|
||||||
|
'User'
|
||||||
|
'Tty'
|
||||||
|
'Env'
|
||||||
|
'Labels'
|
||||||
|
'Cmd'
|
||||||
|
'Entrypoint'
|
||||||
|
'Image'
|
||||||
|
'Volumes'
|
||||||
|
'WorkingDir'
|
||||||
|
'NetworkDisabled'
|
||||||
|
'ExposedPorts'
|
||||||
|
'HostConfig'
|
||||||
|
]
|
||||||
|
|
||||||
|
exports.validHostConfigOptions = [
|
||||||
|
'Binds'
|
||||||
|
'Links'
|
||||||
|
'Memory'
|
||||||
|
'MemorySwap'
|
||||||
|
'MemoryReservation'
|
||||||
|
'KernelMemory'
|
||||||
|
'CpuShares'
|
||||||
|
'CpuPeriod'
|
||||||
|
'CpuQuota'
|
||||||
|
'CpusetCpus'
|
||||||
|
'CpusetMems'
|
||||||
|
'BlkioWeight'
|
||||||
|
'BlkioWeightDevice'
|
||||||
|
'BlkioDeviceReadBps'
|
||||||
|
'BlkioDeviceWriteBps'
|
||||||
|
'BlkioDeviceReadIOps'
|
||||||
|
'BlkioDeviceWriteIOps'
|
||||||
|
'MemorySwappiness'
|
||||||
|
'OomKillDisable'
|
||||||
|
'OomScoreAdj'
|
||||||
|
'PidMode'
|
||||||
|
'PortBindings'
|
||||||
|
'PublishAllPorts'
|
||||||
|
'Privileged'
|
||||||
|
'ReadonlyRootfs'
|
||||||
|
'Dns'
|
||||||
|
'DnsOptions'
|
||||||
|
'DnsSearch'
|
||||||
|
'ExtraHosts'
|
||||||
|
'VolumesFrom'
|
||||||
|
'CapAdd'
|
||||||
|
'CapDrop'
|
||||||
|
'GroupAdd'
|
||||||
|
'RestartPolicy'
|
||||||
|
'NetworkMode'
|
||||||
|
'Devices'
|
||||||
|
'Ulimits'
|
||||||
|
'SecurityOpt'
|
||||||
|
'ShmSize'
|
||||||
|
]
|
||||||
|
|
||||||
|
exports.validateKeys = (options, validSet) ->
|
||||||
|
Promise.try ->
|
||||||
|
return if !options?
|
||||||
|
keys = _.keys(options)
|
||||||
|
invalidKeys = []
|
||||||
|
_.each keys, (key) ->
|
||||||
|
invalidKeys.push(key) if !_.includes(validSet, key)
|
||||||
|
throw new Error("Using #{invalidKeys.join(', ')} is not allowed.") if !_.isEmpty(invalidKeys)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user