Skip to content
This repository has been archived by the owner on Jul 19, 2021. It is now read-only.

Commit

Permalink
more tests + testability improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
jeroenpeeters committed Mar 30, 2017
1 parent 22c4155 commit cf7173e
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 56 deletions.
101 changes: 45 additions & 56 deletions src/coffee/compose.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,50 @@ module.exports = (config) ->
delete service.privileged
delete service.tmpfs

_migrateLinksToDependsOn: migrateLinksToDependsOn = (serviceName, service) ->
if service.links
links = (service.links.map (l) -> l.split(':')[0])
deps = composeLib.transformDependsOnToObject(service.depends_on) or {}
for l in links
deps[l] = condition: 'service_started' unless deps[l]
service.depends_on = deps
delete service.links

_resolvePath: resolvePath = (root, path) ->
path = path[1...] if path[0] is '/'
resolvep root, path

_addDockerMapping: addDockerMapping = (serviceName, service) ->
if service.labels?['bigboat.container.map_docker'] is 'true'
service.volumes = [] unless service.volumes
service.volumes.push '/var/run/docker.sock:/var/run/docker.sock'

_addExtraLabels: addExtraLabels = (serviceName, service) ->
service.labels = _.extend {}, service.labels,
'bigboat.domain': config.domain
'bigboat.tld': config.tld

_addVolumeMapping: addVolumeMapping = (serviceName, service, options) ->
bucketPath = path.join config.dataDir, config.domain, options.storageBucket if options.storageBucket
service.volumes = service.volumes?.map (v) ->
vsplit = v.split ':'
try
if vsplit.length is 2
if vsplit[1] in ['rw', 'ro']
v
else if bucketPath
"#{resolvePath bucketPath, vsplit[0]}:#{vsplit[1]}"
else vsplit[1]
else if vsplit.length is 3
if bucketPath
"#{resolvePath bucketPath, vsplit[0]}:#{vsplit[1]}:#{vsplit[2]}"
else "#{vsplit[1]}:#{vsplit[2]}"
else v
catch e
console.error "Error while mapping volumes. Root: #{bucketPath}, path: #{v}", e
null
service.volumes = service.volumes.filter((s) -> s) if service.volumes

augmentCompose: (instance, options, doc) ->
addNetworkContainer = (serviceName, service) ->
if service.labels['bigboat.service.type'] in ['service', 'oneoff']
Expand Down Expand Up @@ -57,67 +101,12 @@ module.exports = (config) ->

else service.network_mode = "service:bb-net-#{service.labels['bigboat.service.name']}"

resolvePath = (root, path) ->
path = path[1...] if path[0] is '/'
resolvep root, path

addVolumeMapping = (serviceName, service) ->
bucketPath = path.join config.dataDir, config.domain, options.storageBucket if options.storageBucket
service.volumes = service.volumes?.map (v) ->
vsplit = v.split ':'
try
if vsplit.length is 2
if vsplit[1] in ['rw', 'ro']
v
else if bucketPath
"#{resolvePath bucketPath, vsplit[0]}:#{vsplit[1]}"
else vsplit[1]
else if vsplit.length is 3
if bucketPath
"#{resolvePath bucketPath, vsplit[0]}:#{vsplit[1]}:#{vsplit[2]}"
else "#{vsplit[1]}"
else v
catch e
console.error "Error while mapping volumes. Root: #{bucketPath}, path: #{v}", e
null
delete service.volumes unless service.volumes
service.volumes = service.volumes.filter((s) -> s) if service.volumes

migrateLinksToDependsOn = (serviceName, service) ->
if service.links
links = (service.links.map (l) -> l.split(':')[0])
deps = composeLib.transformDependsOnToObject(service.depends_on) or {}
for l in links
deps[l] = condition: 'service_started' unless deps[l]
service.depends_on = deps
delete service.links

migrateLogging = (serviceName, service) ->
# if log_driver is set, that means we are in a compose v1 and logging is not present, no need to merge
if service.log_driver
service.logging =
driver: service.log_driver
service.logging.options = service.log_opt if service.log_opt
delete service.log_driver
delete service.log_opt

addExtraLabels = (serviceName, service) ->
service.labels = _.extend {}, service.labels,
'bigboat.domain': config.domain
'bigboat.tld': config.tld

addDockerMapping = (serviceName, service) ->
if service.labels['bigboat.container.map_docker'] is 'true'
service.volumes = [] unless service.volumes
service.volumes.push '/var/run/docker.sock:/var/run/docker.sock'

for serviceName, service of doc.services
migrateLinksToDependsOn serviceName, service
addExtraLabels serviceName, service
addNetworkContainer serviceName, service
addVolumeMapping serviceName, service
addVolumeMapping serviceName, service, options
addDockerMapping serviceName, service
migrateLogging serviceName, service
restrictCompose serviceName, service

doc.version = '2.1'
Expand Down
97 changes: 97 additions & 0 deletions tests/coffee/compose.test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,100 @@ describe 'Compose', ->
assert.equal doc.networks?, true
compose({}).augmentCompose '', {}, doc
assert.equal doc.networks?, false

describe '_migrateLinksToDependsOn', ->
it 'should leaf the document untouched when there are no links', ->
doc = services: www: image: 'someimage'
compose({})._migrateLinksToDependsOn '', doc
assert.deepEqual doc, services: www: image: 'someimage'
it 'should merge all links with all depends_on (as list) services', ->
service =
links: ['db']
depends_on: ['some_other_service']
compose({})._migrateLinksToDependsOn '', service
assert.deepEqual service, depends_on:
db: {condition: 'service_started'}
some_other_service: {condition: 'service_started'}
it 'should merge all links with all depends_on (as object) services', ->
service =
links: ['db']
depends_on: some_other_service: condition: 'some_condition'
compose({})._migrateLinksToDependsOn '', service
assert.deepEqual service, depends_on:
db: {condition: 'service_started'}
some_other_service: {condition: 'some_condition'}
it 'should prefer a dependency from depends_on over one from links if they are the same', ->
service =
links: ['db']
depends_on: db: condition: 'my_specific_condition'
compose({})._migrateLinksToDependsOn '', service
assert.deepEqual service, depends_on:
db: {condition: 'my_specific_condition'}

describe '_resolvePath', ->
it 'should resolve a path relative to a given root', ->
c = compose({})
assert.equal c._resolvePath('/some/root', '/my/rel/path'), '/some/root/my/rel/path'
assert.equal c._resolvePath('/some/root/', '/my/rel/path'), '/some/root/my/rel/path'
assert.equal c._resolvePath('/some/root', 'my/rel/path'), '/some/root/my/rel/path'
assert.equal c._resolvePath('/some/root', './my/rel/path'), '/some/root/my/rel/path'
assert.equal c._resolvePath('/some/root', '/other/../my/rel/path'), '/some/root/my/rel/path'
assert.equal c._resolvePath('/some/root/', '/some/root/../../one/level/up'), '/some/root/one/level/up'
it 'should throw an error when a relative path resolves outside of the given root', ->
assert.throws ->
compose({})._resolvePath '/some/root/', '../one/level/up'
, Error
assert.throws ->
compose({})._resolvePath '/some/root/', '/../../.././one/level/up'
, Error

describe '_addDockerMapping', ->
it 'should add a volume mapping to the docker socket only when the value of bigboat.container.map_docker label is true', ->
service =
volumes: ['existing_volume']
labels: 'bigboat.container.map_docker': 'true'
compose({})._addDockerMapping '', service
assert.deepEqual service, Object.assign {volumes: ['existing_volume', '/var/run/docker.sock:/var/run/docker.sock']}, service
it 'should not do anything when the label is missing', ->
service = volumes: ['existing_volume']
compose({})._addDockerMapping '', service
assert.deepEqual service, Object.assign {volumes: ['existing_volume']}, service

describe '_addExtraLabels', ->
it 'should add bigboat domain and tld labels based on configuration', ->
service = labels: existing_label: 'value'
compose({domain:'google', tld:'com'})._addExtraLabels '', service
assert.deepEqual service, labels:
existing_label: 'value'
'bigboat.domain': 'google'
'bigboat.tld': 'com'

describe '_addVolumeMapping', ->
volumeTest = (inputVolume, expectedVolume, opts = {storageBucket: 'bucket1'}) ->
c = compose dataDir: '/local/data/', domain: 'google'
service = volumes: [inputVolume]
c._addVolumeMapping '', service, opts
assert.deepEqual service, volumes: [expectedVolume]
it 'should root a volume to a base path (data bucket)', ->
volumeTest '/my/mapping:/internal/volume', '/local/data/google/bucket1/my/mapping:/internal/volume'
it 'should remove a volume\'s mapping when no storage bucket is given (no persistence)', ->
volumeTest '/my/mapping:/internal/volume', '/internal/volume', {}
it 'should leave a :rw postfix intact', ->
volumeTest '/my/mapping:/internal/volume:rw', '/local/data/google/bucket1/my/mapping:/internal/volume:rw'
it 'should leave a :ro postfix intact', ->
volumeTest '/my/mapping:/internal/volume:ro', '/local/data/google/bucket1/my/mapping:/internal/volume:ro'
it 'should leave a postfix intact when no storage bucket is given', ->
volumeTest '/my/mapping:/internal/volume:rw', '/internal/volume:rw', {}
it 'should not do anything to an unmapped volume', ->
volumeTest '/internal/volume', '/internal/volume'
it 'should not do anything to an unmapped volume when no data bucket is given', ->
volumeTest '/internal/volume', '/internal/volume', {}
it 'should not do anything to an unmapped volume with :ro when no data bucket is given', ->
volumeTest '/internal/volume:ro', '/internal/volume:ro', {}
it 'should not do anything to an unmapped volume with :rw', ->
volumeTest '/internal/volume:rw', '/internal/volume:rw'
it 'should discard a volume with a mapping that resolves outside of the bucket root', ->
c = compose dataDir: '/local/data/', domain: 'google'
service = volumes: ['../../my-malicious-volume/:/internal']
c._addVolumeMapping '', service, storageBucket: 'bucket1'
assert.deepEqual service, volumes: []

0 comments on commit cf7173e

Please sign in to comment.