balena-supervisor/test/16-ports.spec.coffee
Cameron Diver f3264862ca
fix: Normalize ports from compose file on instantiation
Adjacent ports are always grouped together by docker when reporting the
container state (from an inspect), so adjacent ports defined in the
compose file would not match as they would not have been normalized.

We make sure to always normalize the input port configuration, so that
it will match the docker output (if it should).

We also don't sort in the fromComposePorts function anymore as that is
handled by the normalize function.

Closes: #897
Change-type: patch
Signed-off-by: Cameron Diver <cameron@balena.io>
2019-02-08 15:14:07 +00:00

337 lines
8.1 KiB
CoffeeScript

m = require 'mochainon'
{ expect } = m.chai
{ PortMap } = require '../src/compose/ports'
describe 'Ports', ->
describe 'Port string parsing', ->
it 'should correctly parse a port string without a range', ->
expect(new PortMap('80')).to.deep.equal(new PortMap({
internalStart: 80
internalEnd: 80
externalStart: 80
externalEnd: 80
protocol: 'tcp'
host: ''
}))
expect(new PortMap('80:80')).to.deep.equal(new PortMap({
internalStart: 80
internalEnd: 80
externalStart: 80
externalEnd: 80
protocol: 'tcp'
host: ''
}))
it 'should correctly parse a port string without an external range', ->
expect(new PortMap('80-90')).to.deep.equal(new PortMap({
internalStart: 80
internalEnd: 90
externalStart: 80
externalEnd: 90
protocol: 'tcp'
host: ''
}))
it 'should correctly parse a port string with a range', ->
expect(new PortMap('80-100:100-120')).to.deep.equal(new PortMap({
internalStart: 100
internalEnd: 120
externalStart: 80
externalEnd: 100
protocol: 'tcp'
host: ''
}))
it 'should correctly parse a protocol', ->
expect(new PortMap('80/udp')).to.deep.equal(new PortMap({
internalStart: 80
internalEnd: 80
externalStart: 80
externalEnd: 80
protocol: 'udp'
host: ''
}))
expect(new PortMap('80:80/udp')).to.deep.equal(new PortMap({
internalStart: 80
internalEnd: 80
externalStart: 80
externalEnd: 80
protocol: 'udp'
host: ''
}))
expect(new PortMap('80-90:100-110/udp')).to.deep.equal(new PortMap({
internalStart: 100
internalEnd: 110
externalStart: 80
externalEnd: 90
protocol: 'udp'
host: ''
}))
it 'should throw when the port string is incorrect', ->
expect(-> new PortMap('80-90:80-85')).to.throw
describe 'toDockerOpts', ->
it 'should correctly generate docker options', ->
expect(new PortMap('80').toDockerOpts()).to.deep.equal({
exposedPorts: {
'80/tcp': {}
}
portBindings: {
'80/tcp': [{ HostIp: '', HostPort: '80' }]
}
})
it 'should correctly generate docker options for a port range', ->
expect(new PortMap('80-85').toDockerOpts()).to.deep.equal({
exposedPorts: {
'80/tcp': {}
'81/tcp': {}
'82/tcp': {}
'83/tcp': {}
'84/tcp': {}
'85/tcp': {}
}
portBindings: {
'80/tcp': [{ HostIp: '', HostPort: '80' }]
'81/tcp': [{ HostIp: '', HostPort: '81' }]
'82/tcp': [{ HostIp: '', HostPort: '82' }]
'83/tcp': [{ HostIp: '', HostPort: '83' }]
'84/tcp': [{ HostIp: '', HostPort: '84' }]
'85/tcp': [{ HostIp: '', HostPort: '85' }]
}
})
describe 'fromDockerOpts', ->
it 'should correctly detect a port range', ->
expect(PortMap.fromDockerOpts({
'100/tcp': [{ HostIp: '123', HostPort: 200 }]
'101/tcp': [{ HostIp: '123', HostPort: 201 }]
'102/tcp': [{ HostIp: '123', HostPort: 202 }]
})).to.deep.equal([new PortMap({
internalStart: 100
internalEnd: 102
externalStart: 200
externalEnd: 202
protocol: 'tcp'
host: '123'
})])
it 'should correctly split ports into ranges', ->
expect(PortMap.fromDockerOpts({
'100/tcp': [{ HostIp: '123', HostPort: 200 }]
'101/tcp': [{ HostIp: '123', HostPort: 201 }]
'105/tcp': [{ HostIp: '123', HostPort: 205 }]
'106/tcp': [{ HostIp: '123', HostPort: 206 }]
'110/tcp': [{ HostIp: '123', HostPort: 210 }]
})).to.deep.equal([
new PortMap({
internalStart: 100
internalEnd: 101
externalStart: 200
externalEnd: 201
protocol: 'tcp'
host: '123'
})
new PortMap({
internalStart: 105
internalEnd: 106
externalStart: 205
externalEnd: 206
protocol: 'tcp'
host: '123'
})
new PortMap({
internalStart: 110
internalEnd: 110
externalStart: 210
externalEnd: 210
protocol: 'tcp'
host: '123'
})
])
it 'should correctly consider internal and external ports', ->
expect(PortMap.fromDockerOpts({
'100/tcp': [{ HostIp: '123', HostPort: 200 }]
'101/tcp': [{ HostIp: '123', HostPort: 101 }]
'102/tcp': [{ HostIp: '123', HostPort: 202 }]
})).to.deep.equal([
new PortMap({
internalStart: 100
internalEnd: 100
externalStart: 200
externalEnd: 200
protocol: 'tcp'
host: '123'
})
new PortMap({
internalStart: 101
internalEnd: 101
externalStart: 101
externalEnd: 101
protocol: 'tcp'
host: '123'
})
new PortMap({
internalStart: 102
internalEnd: 102
externalStart: 202
externalEnd: 202
protocol: 'tcp'
host: '123'
})
])
it 'should consider the host when generating ranges', ->
expect(PortMap.fromDockerOpts({
'100/tcp': [{ HostIp: '123', HostPort: 200 }]
'101/tcp': [{ HostIp: '456', HostPort: 201 }]
'102/tcp': [{ HostIp: '456', HostPort: 202 }]
})).to.deep.equal([
new PortMap({
internalStart: 100
internalEnd: 100
externalStart: 200
externalEnd: 200
protocol: 'tcp'
host: '123'
})
new PortMap({
internalStart: 101
internalEnd: 102
externalStart: 201
externalEnd: 202
protocol: 'tcp'
host: '456'
})
])
it 'should consider the protocol when generating ranges', ->
expect(PortMap.fromDockerOpts({
'100/tcp': [{ HostIp: '123', HostPort: 200 }]
'101/udp': [{ HostIp: '123', HostPort: 201 }]
'102/udp': [{ HostIp: '123', HostPort: 202 }]
})).to.deep.equal([
new PortMap({
internalStart: 100
internalEnd: 100
externalStart: 200
externalEnd: 200
protocol: 'tcp'
host: '123'
})
new PortMap({
internalStart: 101
internalEnd: 102
externalStart: 201
externalEnd: 202
protocol: 'udp'
host: '123'
})
])
describe 'Running container comparison', ->
it 'should not consider order when comparing current and target state', ->
portBindings = require('./data/ports/not-ascending/port-bindings.json')
compose = require('./data/ports/not-ascending/compose.json')
portMapsCurrent = PortMap.fromDockerOpts(portBindings)
portMapsTarget = PortMap.fromComposePorts(compose.ports)
expect(portMapsTarget).to.deep.equal(portMapsCurrent)
describe 'fromComposePorts', ->
it 'should normalise compose ports', ->
expect(PortMap.fromComposePorts([
'80:80',
'81:81',
'82:82',
])).to.deep.equal([
new PortMap('80-82')
])
describe 'normalisePortMaps', ->
it 'should correctly normalise PortMap lists', ->
expect(PortMap.normalisePortMaps([
new PortMap('80:90')
new PortMap('81:91')
])).to.deep.equal([
new PortMap('80-81:90-91')
])
expect(PortMap.normalisePortMaps([
new PortMap('80:90')
new PortMap('81:91')
new PortMap('82:92')
new PortMap('83:93')
new PortMap('84:94')
new PortMap('85:95')
new PortMap('86:96')
new PortMap('87:97')
new PortMap('88:98')
new PortMap('89:99')
new PortMap('90:100')
])).to.deep.equal([
new PortMap('80-90:90-100')
])
expect(PortMap.normalisePortMaps([])).to.deep.equal([])
it 'should correctly consider protocols', ->
expect(PortMap.normalisePortMaps([
new PortMap('80:90')
new PortMap('81:91/udp')
])).to.deep.equal([
new PortMap('80:90')
new PortMap('81:91/udp')
])
expect(PortMap.normalisePortMaps([
new PortMap('80:90')
new PortMap('100:110/udp')
new PortMap('81:91')
])).to.deep.equal([
new PortMap('80-81:90-91')
new PortMap('100:110/udp')
])
# This shouldn't ever be provided, but it shows the algorithm
# working properly
expect(PortMap.normalisePortMaps([
new PortMap('80:90')
new PortMap('81:91/udp')
new PortMap('81:91')
])).to.deep.equal([
new PortMap('80-81:90-91')
new PortMap('81:91/udp')
])
it 'should correctly consider hosts', ->
expect(PortMap.normalisePortMaps([
new PortMap('127.0.0.1:80:80')
new PortMap('81:81')
])).to.deep.equal([
new PortMap('127.0.0.1:80:80')
new PortMap('81:81')
])
expect(PortMap.normalisePortMaps([
new PortMap('127.0.0.1:80:80')
new PortMap('127.0.0.1:81:81')
])).to.deep.equal([
new PortMap('127.0.0.1:80-81:80-81')
])