mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2024-12-25 16:31:05 +00:00
416170bc05
The docker EXPOSE directive and corresponding docker-compose `expose` service configuration serves as documentation/metadata that a container listens on a certain port that may be used for service discovery but it doesn't have any real impact on the ability for other containers on the same network to access the exposed service via the port. In newer engine implementations, this property may conflict with other network configurations, and prevent the container from being started by the docker engine (see #2211). This PR removes code that would manage the expose property and takes the property out of the whitelist. A composition with the `expose` property will result in the log message `Ignoring unsupported or unknown compose fields: expose`. While this change should not have operational impact, it still removes a previously supported configuration and as such there is a chance of it being a breaking change for some applications. For this reason it is being published as a new major version. Change-type: major Closes: #2211
388 lines
9.8 KiB
TypeScript
388 lines
9.8 KiB
TypeScript
import { PortMap, PortRange } from '~/src/compose/ports';
|
|
import { expect } from 'chai';
|
|
|
|
// Force cast `PortMap` as a public version so we can test it
|
|
const PortMapPublic = PortMap as any as new (
|
|
portStrOrObj: string | PortRange,
|
|
) => PortMap;
|
|
|
|
describe('compose/ports', function () {
|
|
describe('Port string parsing', function () {
|
|
it('should correctly parse a port string without a range', function () {
|
|
expect(new PortMapPublic('80')).to.deep.equal(
|
|
new PortMapPublic({
|
|
internalStart: 80,
|
|
internalEnd: 80,
|
|
externalStart: 80,
|
|
externalEnd: 80,
|
|
protocol: 'tcp',
|
|
host: '',
|
|
}),
|
|
);
|
|
|
|
expect(new PortMapPublic('80:80')).to.deep.equal(
|
|
new PortMapPublic({
|
|
internalStart: 80,
|
|
internalEnd: 80,
|
|
externalStart: 80,
|
|
externalEnd: 80,
|
|
protocol: 'tcp',
|
|
host: '',
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should correctly parse a port string without an external range', () =>
|
|
expect(new PortMapPublic('80-90')).to.deep.equal(
|
|
new PortMapPublic({
|
|
internalStart: 80,
|
|
internalEnd: 90,
|
|
externalStart: 80,
|
|
externalEnd: 90,
|
|
protocol: 'tcp',
|
|
host: '',
|
|
}),
|
|
));
|
|
|
|
it('should correctly parse a port string with a range', () =>
|
|
expect(new PortMapPublic('80-100:100-120')).to.deep.equal(
|
|
new PortMapPublic({
|
|
internalStart: 100,
|
|
internalEnd: 120,
|
|
externalStart: 80,
|
|
externalEnd: 100,
|
|
protocol: 'tcp',
|
|
host: '',
|
|
}),
|
|
));
|
|
|
|
it('should correctly parse a protocol', function () {
|
|
expect(new PortMapPublic('80/udp')).to.deep.equal(
|
|
new PortMapPublic({
|
|
internalStart: 80,
|
|
internalEnd: 80,
|
|
externalStart: 80,
|
|
externalEnd: 80,
|
|
protocol: 'udp',
|
|
host: '',
|
|
}),
|
|
);
|
|
|
|
expect(new PortMapPublic('80:80/udp')).to.deep.equal(
|
|
new PortMapPublic({
|
|
internalStart: 80,
|
|
internalEnd: 80,
|
|
externalStart: 80,
|
|
externalEnd: 80,
|
|
protocol: 'udp',
|
|
host: '',
|
|
}),
|
|
);
|
|
|
|
expect(new PortMapPublic('80-90:100-110/udp')).to.deep.equal(
|
|
new PortMapPublic({
|
|
internalStart: 100,
|
|
internalEnd: 110,
|
|
externalStart: 80,
|
|
externalEnd: 90,
|
|
protocol: 'udp',
|
|
host: '',
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should throw when the port string is incorrect', () =>
|
|
expect(() => new PortMapPublic('80-90:80-85')).to.throw);
|
|
});
|
|
|
|
describe('toDockerOpts', function () {
|
|
it('should correctly generate docker options', () =>
|
|
expect(new PortMapPublic('80').toDockerOpts()).to.deep.equal({
|
|
portBindings: {
|
|
'80/tcp': [{ HostIp: '', HostPort: '80' }],
|
|
},
|
|
}));
|
|
|
|
it('should correctly generate docker options for a port range', () =>
|
|
expect(new PortMapPublic('80-85').toDockerOpts()).to.deep.equal({
|
|
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', function () {
|
|
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 PortMapPublic({
|
|
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 PortMapPublic({
|
|
internalStart: 100,
|
|
internalEnd: 101,
|
|
externalStart: 200,
|
|
externalEnd: 201,
|
|
protocol: 'tcp',
|
|
host: '123',
|
|
}),
|
|
new PortMapPublic({
|
|
internalStart: 105,
|
|
internalEnd: 106,
|
|
externalStart: 205,
|
|
externalEnd: 206,
|
|
protocol: 'tcp',
|
|
host: '123',
|
|
}),
|
|
new PortMapPublic({
|
|
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 PortMapPublic({
|
|
internalStart: 100,
|
|
internalEnd: 100,
|
|
externalStart: 200,
|
|
externalEnd: 200,
|
|
protocol: 'tcp',
|
|
host: '123',
|
|
}),
|
|
new PortMapPublic({
|
|
internalStart: 101,
|
|
internalEnd: 101,
|
|
externalStart: 101,
|
|
externalEnd: 101,
|
|
protocol: 'tcp',
|
|
host: '123',
|
|
}),
|
|
new PortMapPublic({
|
|
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 PortMapPublic({
|
|
internalStart: 100,
|
|
internalEnd: 100,
|
|
externalStart: 200,
|
|
externalEnd: 200,
|
|
protocol: 'tcp',
|
|
host: '123',
|
|
}),
|
|
new PortMapPublic({
|
|
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 PortMapPublic({
|
|
internalStart: 100,
|
|
internalEnd: 100,
|
|
externalStart: 200,
|
|
externalEnd: 200,
|
|
protocol: 'tcp',
|
|
host: '123',
|
|
}),
|
|
new PortMapPublic({
|
|
internalStart: 101,
|
|
internalEnd: 102,
|
|
externalStart: 201,
|
|
externalEnd: 202,
|
|
protocol: 'udp',
|
|
host: '123',
|
|
}),
|
|
]));
|
|
|
|
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 PortMapPublic({
|
|
internalStart: 100,
|
|
internalEnd: 100,
|
|
externalStart: 200,
|
|
externalEnd: 200,
|
|
protocol: 'tcp',
|
|
host: '123',
|
|
}),
|
|
new PortMapPublic({
|
|
internalStart: 100,
|
|
internalEnd: 100,
|
|
externalStart: 201,
|
|
externalEnd: 201,
|
|
protocol: 'tcp',
|
|
host: '123',
|
|
}),
|
|
]));
|
|
});
|
|
|
|
describe('Running container comparison', () =>
|
|
it('should not consider order when comparing current and target state', function () {
|
|
const portBindings = require('~/test-data/ports/not-ascending/port-bindings.json');
|
|
const compose = require('~/test-data/ports/not-ascending/compose.json');
|
|
const portMapsCurrent = PortMap.fromDockerOpts(portBindings);
|
|
const 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 PortMapPublic('80-82')])));
|
|
|
|
describe('normalisePortMaps', function () {
|
|
it('should correctly normalise PortMap lists', function () {
|
|
expect(
|
|
PortMap.normalisePortMaps([
|
|
new PortMapPublic('80:90'),
|
|
new PortMapPublic('81:91'),
|
|
]),
|
|
).to.deep.equal([new PortMapPublic('80-81:90-91')]);
|
|
|
|
expect(
|
|
PortMap.normalisePortMaps([
|
|
new PortMapPublic('80:90'),
|
|
new PortMapPublic('81:91'),
|
|
new PortMapPublic('82:92'),
|
|
new PortMapPublic('83:93'),
|
|
new PortMapPublic('84:94'),
|
|
new PortMapPublic('85:95'),
|
|
new PortMapPublic('86:96'),
|
|
new PortMapPublic('87:97'),
|
|
new PortMapPublic('88:98'),
|
|
new PortMapPublic('89:99'),
|
|
new PortMapPublic('90:100'),
|
|
]),
|
|
).to.deep.equal([new PortMapPublic('80-90:90-100')]);
|
|
|
|
expect(PortMap.normalisePortMaps([])).to.deep.equal([]);
|
|
});
|
|
|
|
it('should correctly consider protocols', function () {
|
|
expect(
|
|
PortMap.normalisePortMaps([
|
|
new PortMapPublic('80:90'),
|
|
new PortMapPublic('81:91/udp'),
|
|
]),
|
|
).to.deep.equal([
|
|
new PortMapPublic('80:90'),
|
|
new PortMapPublic('81:91/udp'),
|
|
]);
|
|
|
|
expect(
|
|
PortMap.normalisePortMaps([
|
|
new PortMapPublic('80:90'),
|
|
new PortMapPublic('100:110/udp'),
|
|
new PortMapPublic('81:91'),
|
|
]),
|
|
).to.deep.equal([
|
|
new PortMapPublic('80-81:90-91'),
|
|
new PortMapPublic('100:110/udp'),
|
|
]);
|
|
|
|
// This shouldn't ever be provided, but it shows the algorithm
|
|
// working properly
|
|
expect(
|
|
PortMap.normalisePortMaps([
|
|
new PortMapPublic('80:90'),
|
|
new PortMapPublic('81:91/udp'),
|
|
new PortMapPublic('81:91'),
|
|
]),
|
|
).to.deep.equal([
|
|
new PortMapPublic('80-81:90-91'),
|
|
new PortMapPublic('81:91/udp'),
|
|
]);
|
|
});
|
|
|
|
it('should correctly consider hosts', function () {
|
|
expect(
|
|
PortMap.normalisePortMaps([
|
|
new PortMapPublic('127.0.0.1:80:80'),
|
|
new PortMapPublic('81:81'),
|
|
]),
|
|
).to.deep.equal([
|
|
new PortMapPublic('127.0.0.1:80:80'),
|
|
new PortMapPublic('81:81'),
|
|
]);
|
|
|
|
expect(
|
|
PortMap.normalisePortMaps([
|
|
new PortMapPublic('127.0.0.1:80:80'),
|
|
new PortMapPublic('127.0.0.1:81:81'),
|
|
]),
|
|
).to.deep.equal([new PortMapPublic('127.0.0.1:80-81:80-81')]);
|
|
});
|
|
});
|
|
});
|