From 6ccd2178c18acded013e888a296e265bc0315728 Mon Sep 17 00:00:00 2001 From: Christina Wang Date: Tue, 17 May 2022 23:40:50 +0000 Subject: [PATCH] Use Mounts API for engine socket feature label When upgrading to this Supervisor version, containers using the engine feature label will be restarted. Relates-to: https://github.com/balena-os/balena-supervisor/pull/1780 Closes: https://github.com/balena-os/balena-engine/issues/220 Closes: #1933 Change-type: major Signed-off-by: Christina Wang --- src/compose/types/service.ts | 1 + src/compose/utils.ts | 25 +++++++++++++-------- test/src/compose/service.spec.ts | 38 ++++++++++++++++++++++++-------- 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/compose/types/service.ts b/src/compose/types/service.ts index 6c79f552..9cf05cad 100644 --- a/src/compose/types/service.ts +++ b/src/compose/types/service.ts @@ -136,6 +136,7 @@ export const LongBind = t.brand( l.type === 'bind' && isAbsolute(l.source), 'LongBind', ); +export type LongBind = t.TypeOf; // 'source' is disallowed for tmpfs interface LongTmpfsBrand { diff --git a/src/compose/utils.ts b/src/compose/utils.ts index 6f130f02..ab3972b1 100644 --- a/src/compose/utils.ts +++ b/src/compose/utils.ts @@ -15,6 +15,7 @@ import { ServiceConfig, ServiceHealthcheck, LongDefinition, + LongBind, } from './types/service'; import log from '../lib/supervisor-console'; @@ -345,14 +346,18 @@ export async function addFeaturesFromLabels( ? service.config.volumes.push('/lib/firmware:/lib/firmware') : null, 'io.balena.features.balena-socket': () => { - service.config.volumes.push( - `${constants.dockerSocket}:${constants.containerDockerSocket}`, - ); + service.config.volumes.push({ + type: 'bind', + source: constants.dockerSocket, + target: constants.containerDockerSocket, + } as LongBind); // Maintain the /var/run mount for backwards compatibility - service.config.volumes.push( - `${constants.dockerSocket}:${constants.dockerSocket}`, - ); + service.config.volumes.push({ + type: 'bind', + source: constants.dockerSocket, + target: constants.dockerSocket, + } as LongBind); if (service.config.environment['DOCKER_HOST'] == null) { service.config.environment[ @@ -361,9 +366,11 @@ export async function addFeaturesFromLabels( } // We keep balena.sock for backwards compatibility if (constants.dockerSocket !== '/var/run/balena.sock') { - service.config.volumes.push( - `${constants.dockerSocket}:/var/run/balena.sock`, - ); + service.config.volumes.push({ + type: 'bind', + source: constants.dockerSocket, + target: '/var/run/balena.sock', + } as LongBind); } }, 'io.balena.features.balena-api': () => { diff --git a/test/src/compose/service.spec.ts b/test/src/compose/service.spec.ts index 8698c054..c85cc330 100644 --- a/test/src/compose/service.spec.ts +++ b/test/src/compose/service.spec.ts @@ -594,7 +594,7 @@ describe('compose/service', () => { describe('Feature labels', () => { describe('io.balena.features.balena-socket', () => { - it('should mount the socket in the container an set DOCKER_HOST with the proper location', async () => { + it('should mount the socket in the container and set DOCKER_HOST with the proper location', async () => { const service = await Service.fromComposeObject( { appId: 123456, @@ -607,8 +607,22 @@ describe('compose/service', () => { { appName: 'test' } as any, ); - expect(service.config.volumes).to.include.members([ - `${constants.dockerSocket}:${constants.containerDockerSocket}`, + expect(service.config.volumes).to.deep.include.members([ + { + type: 'bind', + source: constants.dockerSocket, + target: constants.containerDockerSocket, + }, + { + type: 'bind', + source: constants.dockerSocket, + target: constants.dockerSocket, + }, + { + type: 'bind', + source: constants.dockerSocket, + target: '/var/run/balena.sock', + }, ]); expect(service.config.environment['DOCKER_HOST']).to.equal( @@ -1186,11 +1200,13 @@ describe('compose/service', () => { * Service -> container (toDockerContainer) */ // Inject bind mounts (as feature labels would) - // Bind mounts added under feature labels use the short syntax (for now) + // Bind mounts added under feature labels use the short syntax, except for the engine label service.config.volumes.push('/var/log/journal:/var/log/journal:ro'); - service.config.volumes.push( - `${constants.dockerSocket}:${constants.containerDockerSocket}`, - ); + service.config.volumes.push({ + type: 'bind', + source: constants.dockerSocket, + target: constants.containerDockerSocket, + } as ServiceT.LongBind); const ctn = service.toDockerContainer({ deviceName: 'thicc_nucc', @@ -1208,9 +1224,14 @@ describe('compose/service', () => { ReadOnly: true, }, { Type: 'tmpfs', Target: '/home/tmp' }, + { + Type: 'bind', + Source: constants.dockerSocket, + Target: constants.containerDockerSocket, + }, ]); - // bind mounts should be filtered out + // bind mounts except for the engine feature label should be filtered out expect(ctn.HostConfig) .to.have.property('Mounts') .that.does.not.deep.include.members([ @@ -1226,7 +1247,6 @@ describe('compose/service', () => { `/tmp/balena-supervisor/services/${appId}/${serviceName}:/tmp/resin`, `/tmp/balena-supervisor/services/${appId}/${serviceName}:/tmp/balena`, '/var/log/journal:/var/log/journal:ro', - `${constants.dockerSocket}:${constants.containerDockerSocket}`, ]); // Tmpfs volumes defined through compose's service.tmpfs are under HostConfig.Tmpfs.