Merge pull request #969 from balena-io/968-multiple-ports

Handle multiple host ports pointing to a single container port
This commit is contained in:
CameronDiver 2019-04-25 16:11:35 +01:00 committed by GitHub
commit 84c03f89ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 52 additions and 15 deletions

View File

@ -90,24 +90,25 @@ export class PortMap {
public static fromDockerOpts(portBindings: PortBindings): PortMap[] { public static fromDockerOpts(portBindings: PortBindings): PortMap[] {
// Create a list of portBindings, rather than the map (which we can't // Create a list of portBindings, rather than the map (which we can't
// order) // order)
const portMaps = _.map(portBindings, (hostObj, internalStr) => { const portMaps = _.flatMap(portBindings, (hostObj, internalStr) => {
const match = internalStr.match(DOCKER_OPTS_PORTS_REGEX); const match = internalStr.match(DOCKER_OPTS_PORTS_REGEX);
if (match == null) { if (match == null) {
throw new Error(`Could not parse docker port output: ${internalStr}`); throw new Error(`Could not parse docker port output: ${internalStr}`);
} }
const internal = parseInt(match[1], 10); const internal = parseInt(match[1], 10);
const external = parseInt(hostObj[0].HostPort, 10);
const host = hostObj[0].HostIp;
const proto = match[2] || 'tcp'; const proto = match[2] || 'tcp';
return new PortMap({ return _.map(hostObj, ({ HostIp, HostPort }) => {
internalStart: internal, const external = parseInt(HostPort, 10);
internalEnd: internal, const host = HostIp;
externalStart: external, return new PortMap({
externalEnd: external, internalStart: internal,
protocol: proto, internalEnd: internal,
host, externalStart: external,
externalEnd: external,
protocol: proto,
host,
});
}); });
}); });

View File

@ -775,7 +775,12 @@ export class Service {
_.each(this.config.portMaps, pmap => { _.each(this.config.portMaps, pmap => {
const { exposedPorts, portBindings } = pmap.toDockerOpts(); const { exposedPorts, portBindings } = pmap.toDockerOpts();
_.merge(exposed, exposedPorts); _.merge(exposed, exposedPorts);
_.merge(ports, portBindings); _.mergeWith(ports, portBindings, (destVal, srcVal) => {
if (destVal == null) {
return srcVal;
}
return destVal.concat(srcVal);
});
}); });
// We also want to merge the compose and image exposedPorts // We also want to merge the compose and image exposedPorts

View File

@ -198,13 +198,16 @@ describe 'deviceState', ->
prepare() prepare()
@db = new DB() @db = new DB()
@config = new Config({ @db }) @config = new Config({ @db })
@logger = {
clearOutOfDateDBLogs: ->
}
eventTracker = { eventTracker = {
track: console.log track: console.log
} }
stub(Service, 'extendEnvVars').callsFake (env) -> stub(Service, 'extendEnvVars').callsFake (env) ->
env['ADDITIONAL_ENV_VAR'] = 'foo' env['ADDITIONAL_ENV_VAR'] = 'foo'
return env return env
@deviceState = new DeviceState({ @db, @config, eventTracker }) @deviceState = new DeviceState({ @db, @config, eventTracker, @logger })
stub(@deviceState.applications.docker, 'getNetworkGateway').returns(Promise.resolve('172.17.0.1')) stub(@deviceState.applications.docker, 'getNetworkGateway').returns(Promise.resolve('172.17.0.1'))
stub(@deviceState.applications.images, 'inspectByName').callsFake -> stub(@deviceState.applications.images, 'inspectByName').callsFake ->
Promise.try -> Promise.try ->

View File

@ -20,7 +20,10 @@ initModels = (filename) ->
track: stub().callsFake (ev, props) -> track: stub().callsFake (ev, props) ->
console.log(ev, props) console.log(ev, props)
} }
@deviceState = new DeviceState({ @db, @config, @eventTracker }) @logger = {
clearOutOfDateDBLogs: ->
}
@deviceState = new DeviceState({ @db, @config, @eventTracker, @logger })
@apiBinder = new APIBinder({ @db, @config, @eventTracker, @deviceState }) @apiBinder = new APIBinder({ @db, @config, @eventTracker, @deviceState })
@db.init() @db.init()
.then => .then =>

View File

@ -123,7 +123,10 @@ describe 'ApplicationManager', ->
eventTracker = { eventTracker = {
track: console.log track: console.log
} }
@deviceState = new DeviceState({ @db, @config, eventTracker }) @logger = {
clearOutOfDateDBLogs: ->
}
@deviceState = new DeviceState({ @db, @config, eventTracker, @logger })
@applications = @deviceState.applications @applications = @deviceState.applications
stub(@applications.images, 'inspectByName').callsFake (imageName) -> stub(@applications.images, 'inspectByName').callsFake (imageName) ->
Promise.resolve({ Promise.resolve({

View File

@ -243,6 +243,28 @@ describe 'Ports', ->
}) })
]) ])
it 'should correctly detect multiple hosts ports on an internal port', ->
expect(PortMap.fromDockerOpts({
'100/tcp': [{ HostIp: '123', HostPort: 200 }, { HostIp: '123', HostPort: 201 }]
})).to.deep.equal([
new PortMap({
internalStart: 100,
internalEnd: 100,
externalStart: 200,
externalEnd: 200,
protocol: 'tcp',
host: '123'
})
new PortMap({
internalStart: 100,
internalEnd: 100,
externalStart: 201,
externalEnd: 201,
protocol: 'tcp',
host: '123'
})
])
describe 'Running container comparison', -> describe 'Running container comparison', ->
it 'should not consider order when comparing current and target state', -> it 'should not consider order when comparing current and target state', ->
portBindings = require('./data/ports/not-ascending/port-bindings.json') portBindings = require('./data/ports/not-ascending/port-bindings.json')