diff --git a/README.md b/README.md index 420ebd273..5d45584ea 100644 --- a/README.md +++ b/README.md @@ -251,9 +251,9 @@ If you have upgraded system packages and find that your tests are failing to ini ### DBus -When developing on macOS you may need to install DBus on the development host. +When developing on macOS you may need to install DBus on the development host if you get errors like `Package dbus-1 was not found in the pkg-config search path.`. -1. `brew install dbus` +1. `brew install dbus` or `sudo port install dbus` 2. `npm ci` On Debian-based systems, `sudo apt install libdbus-1-dev` would be the equivalent. diff --git a/src/compose/service.ts b/src/compose/service.ts index 7072a1a68..b2add49ef 100644 --- a/src/compose/service.ts +++ b/src/compose/service.ts @@ -651,7 +651,7 @@ export class Service { const nameMatch = container.Name.match(/.*_(\d+)_(\d+)(?:_(.*?))?$/); if (nameMatch == null) { throw new InternalInconsistencyError( - `Expected supervised container to have name '___', got: ${container.Name}`, + `Expected supervised container to have name '__(_)', got: ${container.Name}`, ); } @@ -704,8 +704,19 @@ export class Service { } this.config.networkMode = `container:${containerId}`; } + + // Format container name to keep it under 64 characters to make it a legal DNS hostname + const imageIdPart = ('' + this.imageId).substring(0, 10); + const releaseIdPart = ('' + this.releaseId).substring(0, 10); + // Shorten the service name so that it leaves room for the required imageId and releaseId parts ( see fromDockerContainer ) + const serviceNamePart = this.serviceName?.substring(0, 28); + // Use a commit prefix so that all containers will get the same commit suffix in normal cases where the name length is <= 63 + const commitPrefix = this.commit?.substring(0, 12); return { - name: `${this.serviceName}_${this.imageId}_${this.releaseId}_${this.commit}`, + name: `${serviceNamePart}_${imageIdPart}_${releaseIdPart}_${commitPrefix}`.substring( + 0, + 63, + ), Tty: this.config.tty, Cmd: this.config.command, Volumes: volumes, diff --git a/test/unit/compose/service.spec.ts b/test/unit/compose/service.spec.ts index 5c4783c13..1c588a6b2 100644 --- a/test/unit/compose/service.spec.ts +++ b/test/unit/compose/service.spec.ts @@ -7,6 +7,7 @@ import Service from '~/src/compose/service'; import Volume from '~/src/compose/volume'; import * as ServiceT from '~/src/compose/types/service'; import * as constants from '~/lib/constants'; +import Dockerode = require('dockerode'); const configs = { simple: { @@ -464,6 +465,62 @@ describe('compose/service: unit tests', () => { }); }); }); + + describe('Container naming', () => { + function validateExpectationsOnName( + containerCreateOptions: Dockerode.ContainerCreateOptions, + ) { + console.log(containerCreateOptions.name); + const MAX_DNS_HOSTNAME_LENGTH = 63; + expect(containerCreateOptions.name?.length).to.be.lessThanOrEqual( + MAX_DNS_HOSTNAME_LENGTH, + ); + const nameMatch = containerCreateOptions.name?.match( + /.*_(\d+)_(\d+)(?:_(.*?))?$/, + ); + expect(nameMatch).to.be.not.null; + } + + it('should create valid DNS names with long commits', async () => { + const service = await Service.fromComposeObject( + { + appId: 1234567, + appUuid: 'ae8c6ddc272547a49531149bd2dd187f', + serviceId: 1234568, + serviceName: 'test_broker_client', + imageId: '5826138', + releaseId: '2403300', + commit: '72b853b44d0246fd789c89269db742d04a2e5ef9', + }, + { appName: 'test' } as any, + ); + + const containerCreateOptions = service.toDockerContainer({ + deviceName: 'foo', + } as any); + validateExpectationsOnName(containerCreateOptions); + }); + + it('should create valid DNS names with long service names', async () => { + const service = await Service.fromComposeObject( + { + appId: 1234567, + appUuid: 'ae8c6ddc272547a49531149bd2dd187f', + serviceId: 1234568, + serviceName: 'X'.repeat(64), + imageId: '5826138', + releaseId: '2403300', + commit: '72b853b44d0246fd789c89269db742d04a2e5ef9', + }, + { appName: 'test' } as any, + ); + + const containerCreateOptions = service.toDockerContainer({ + deviceName: 'foo', + } as any); + validateExpectationsOnName(containerCreateOptions); + }); + }); }); describe('Comparing services', () => {