diff --git a/src/index.ts b/src/index.ts index ce6f811..7a50f05 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,7 @@ import childProcess from 'child_process' import yaml from 'yaml' +import mapPorts from './port-mapper' + export interface IDockerComposeOptions { cwd?: string executablePath?: string @@ -75,33 +77,6 @@ export type DockerComposePsResult = { }> } -export const mapPorts = ( - ports: string -): Array<{ - mapped?: { address: string; port: number } - exposed: { port: number; protocol: string } -}> => { - const result = !ports - ? [] - : (() => { - return ports.split(',').map((untypedPort) => { - const exposedFragments = untypedPort.trim().split('->') - const [port, protocol] = - exposedFragments.length === 1 - ? exposedFragments[0].split('/') - : exposedFragments[1].split('/') - const [address, mappedPort] = - exposedFragments.length === 2 ? exposedFragments[0].split(':') : [] - return { - exposed: { port: Number(port), protocol }, - ...(address && - mappedPort && { mapped: { port: Number(mappedPort), address } }) - } - }) - })() - return result -} - export const mapPsOutput = (output: string): DockerComposePsResult => { const services = output .split(`\n`) @@ -514,3 +489,5 @@ export const version = async function ( return Promise.reject(error) } } + +export { mapPorts } diff --git a/src/port-mapper.ts b/src/port-mapper.ts new file mode 100644 index 0000000..f7c3d11 --- /dev/null +++ b/src/port-mapper.ts @@ -0,0 +1,31 @@ +const mapPorts = ( + ports: string +): Array<{ + mapped?: { address: string; port: number } + exposed: { port: number; protocol: string } +}> => { + const result = !ports + ? [] + : (() => { + return ports.split(',').map((untypedPort) => { + const exposedFragments = untypedPort.trim().split('->') + + console.log(exposedFragments) + + const [port, protocol] = + exposedFragments.length === 1 + ? exposedFragments[0].split('/') + : exposedFragments[1].split('/') + const [address, mappedPort] = + exposedFragments.length === 2 ? exposedFragments[0].split(':') : [] + return { + exposed: { port: Number(port), protocol }, + ...(address && + mappedPort && { mapped: { port: Number(mappedPort), address } }) + } + }) + })() + return result +} + +export default mapPorts diff --git a/test/docker-compose.yml b/test/docker-compose.yml index 059a017..1d4794a 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -6,8 +6,8 @@ services: container_name: compose_test_web command: 'nginx -g "daemon off;"' ports: - - 80:80 - - 443:443 + - '0.0.0.0:80:80' + - '0.0.0.0:443:443' proxy: image: nginx:1.19.9-alpine container_name: compose_test_proxy diff --git a/test/index.test.ts b/test/index.test.ts index de96b82..4ba4fc7 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -699,31 +699,3 @@ test('parse ps output', () => { ] }) }) - -test('map ports', () => { - const noPort = '' - const exposedTcp = '80/tcp' - const mappedExposedTcp = '0.0.0.0:443->443/tcp' - const multipleExposedMappedTcp = '0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp' - - expect(mapPorts(noPort)).toEqual([]) - expect(mapPorts(exposedTcp)).toEqual([ - { exposed: { port: 80, protocol: 'tcp' } } - ]) - expect(mapPorts(mappedExposedTcp)).toEqual([ - { - exposed: { port: 443, protocol: 'tcp' }, - mapped: { address: '0.0.0.0', port: 443 } - } - ]) - expect(mapPorts(multipleExposedMappedTcp)).toEqual([ - { - exposed: { port: 443, protocol: 'tcp' }, - mapped: { address: '0.0.0.0', port: 443 } - }, - { - exposed: { port: 80, protocol: 'tcp' }, - mapped: { address: '0.0.0.0', port: 80 } - } - ]) -}) diff --git a/test/port-mapper.test.ts b/test/port-mapper.test.ts new file mode 100644 index 0000000..405c794 --- /dev/null +++ b/test/port-mapper.test.ts @@ -0,0 +1,54 @@ +import mapPorts from "../src/port-mapper"; + +test('map ports for empty string', () => { + expect(mapPorts('')).toEqual([]) +}) + +test('map ports for exposed tcp', () => { + expect(mapPorts('80/tcp')).toEqual([ + { exposed: { port: 80, protocol: 'tcp' } } + ]) +}) + +test('map ports for exposed tcp on ivp4 interface', () => { + expect(mapPorts('0.0.0.0:443->443/tcp')).toEqual([ + { + exposed: { port: 443, protocol: 'tcp' }, + mapped: { address: '0.0.0.0', port: 443 } + } + ]) +}) + +test('map multiple tcp ports exposed on ivp4 interfaces', () => { + expect(mapPorts('0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp')).toEqual([ + { + exposed: { port: 443, protocol: 'tcp' }, + mapped: { address: '0.0.0.0', port: 443 } + }, + { + exposed: { port: 80, protocol: 'tcp' }, + mapped: { address: '0.0.0.0', port: 80 } + } + ]) +}) + +test('map multiple tcp ports exposed on ipv4 and ipv6 interfaces', () => { + expect(mapPorts('0.0.0.0:443->443/tcp,:::443->443/tcp, 0.0.0.0:80->80/tcp,:::80->80/tcp')).toEqual([ + { + exposed: { port: 443, protocol: 'tcp' }, + mapped: { address: '0.0.0.0', port: 443 }, + }, + { + exposed: { port: 443, protocol: 'tcp' }, + mapped: { address: ':::', port: 443 }, + }, + { + exposed: { port: 80, protocol: 'tcp' }, + mapped: { address: '0.0.0.0', port: 80 }, + }, + { + exposed: { port: 80, protocol: 'tcp' }, + mapped: { address: ':::', port: 80 }, + }, + ]) +})