From c3cf8fbca25d3f6dae5c58cf29f11b2c89d10353 Mon Sep 17 00:00:00 2001 From: Rich Bayliss Date: Mon, 2 Dec 2019 10:05:31 +0000 Subject: [PATCH] volumes: Allow the use of the 'driver' setting in volumes A compose file can now contain a volume which uses a different driver from the default one; local. Change-type: patch Signed-off-by: Rich Bayliss --- src/application-manager.coffee | 5 ++-- src/compose/volume.ts | 21 +++++++------- test/20-compose-volume.ts | 51 +++++++++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/application-manager.coffee b/src/application-manager.coffee index 79a64d05..5f515b85 100644 --- a/src/application-manager.coffee +++ b/src/application-manager.coffee @@ -666,11 +666,12 @@ module.exports = class ApplicationManager extends EventEmitter Promise.map(JSON.parse(app.services), (service) => @createTargetService(service, configOpts)) .then (services) => - # If a named volume is defined in a service, we add it app-wide so that we can track it and purge it + # If a named volume is defined in a service but NOT in the volumes of the compose file, we add it app-wide so that we can track it and purge it + # !! DEPRECATED, WILL BE REMOVED IN NEXT MAJOR RELEASE !! for s in services serviceNamedVolumes = s.getNamedVolumes() for name in serviceNamedVolumes - volumes[name] = @createTargetVolume(name, app.appId, { labels: {} }) + volumes[name] ?= @createTargetVolume(name, app.appId, { labels: {} }) outApp = { appId: app.appId name: app.name diff --git a/src/compose/volume.ts b/src/compose/volume.ts index f40ba77d..3e3706df 100644 --- a/src/compose/volume.ts +++ b/src/compose/volume.ts @@ -17,34 +17,28 @@ export interface VolumeConstructOpts { export interface VolumeConfig { labels: LabelObject; + driver: string; driverOpts: Docker.VolumeInspectInfo['Options']; } export interface ComposeVolumeConfig { + driver: string; driver_opts: Dictionary; labels: LabelObject; } export class Volume { - public appId: number; - public name: string; - public config: VolumeConfig; - private logger: Logger; private docker: Docker; private constructor( - name: string, - appId: number, - config: VolumeConfig, + public name: string, + public appId: number, + public config: VolumeConfig, opts: VolumeConstructOpts, ) { - this.name = name; - this.appId = appId; - this.logger = opts.logger; this.docker = opts.docker; - this.config = config; } public static fromDockerVolume( @@ -54,6 +48,7 @@ export class Volume { // Convert the docker inspect to the config const config: VolumeConfig = { labels: inspect.Labels || {}, + driver: inspect.Driver, driverOpts: inspect.Options || {}, }; @@ -71,6 +66,7 @@ export class Volume { ) { const filledConfig: VolumeConfig = { driverOpts: config.driver_opts || {}, + driver: config.driver || 'local', labels: ComposeUtils.normalizeLabels(config.labels || {}), }; @@ -83,6 +79,7 @@ export class Volume { public toComposeObject(): ComposeVolumeConfig { return { + driver: this.config.driver, driver_opts: this.config.driverOpts!, labels: this.config.labels, }; @@ -90,6 +87,7 @@ export class Volume { public isEqualConfig(volume: Volume): boolean { return ( + isEqual(this.config.driver, volume.config.driver) && isEqual(this.config.driverOpts, volume.config.driverOpts) && isEqual( Volume.omitSupervisorLabels(this.config.labels), @@ -105,6 +103,7 @@ export class Volume { await this.docker.createVolume({ Name: Volume.generateDockerName(this.appId, this.name), Labels: this.config.labels, + Driver: this.config.driver, DriverOpts: this.config.driverOpts, }); } diff --git a/test/20-compose-volume.ts b/test/20-compose-volume.ts index c2f9a87c..fb7a64fe 100644 --- a/test/20-compose-volume.ts +++ b/test/20-compose-volume.ts @@ -44,9 +44,13 @@ describe('Compose volumes', () => { .to.have.property('config') .that.has.property('driverOpts') .that.deep.equals({}); + expect(volume) + .to.have.property('config') + .that.has.property('driver') + .that.equals('local'); }); - it('should correctly parse compose volumes', () => { + it('should correctly parse compose volumes without an explicit driver', () => { const volume = Volume.fromComposeObject( 'one_volume', 1032480, @@ -80,6 +84,51 @@ describe('Compose volumes', () => { .that.deep.equals({ opt1: 'test', }); + expect(volume) + .to.have.property('config') + .that.has.property('driver') + .that.equals('local'); + }); + + it('should correctly parse compose volumes with an explicit driver', () => { + const volume = Volume.fromComposeObject( + 'one_volume', + 1032480, + { + driver: 'other', + driver_opts: { + opt1: 'test', + }, + labels: { + 'my-label': 'test-label', + }, + }, + opts, + ); + + expect(volume) + .to.have.property('appId') + .that.equals(1032480); + expect(volume) + .to.have.property('name') + .that.equals('one_volume'); + expect(volume) + .to.have.property('config') + .that.has.property('labels') + .that.deep.equals({ + 'io.balena.supervised': 'true', + 'my-label': 'test-label', + }); + expect(volume) + .to.have.property('config') + .that.has.property('driverOpts') + .that.deep.equals({ + opt1: 'test', + }); + expect(volume) + .to.have.property('config') + .that.has.property('driver') + .that.equals('other'); }); });