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 <rich@balena.io>
This commit is contained in:
Rich Bayliss 2019-12-02 10:05:31 +00:00
parent a29784a58c
commit c3cf8fbca2
No known key found for this signature in database
GPG Key ID: E53C4B4D18499E1A
3 changed files with 63 additions and 14 deletions

View File

@ -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

View File

@ -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<string>;
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,
});
}

View File

@ -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');
});
});