mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-02-21 02:01:35 +00:00
Don't attempt to cleanup any target state referenced volumes
The code before this change could potentially remove a volume which should not be removed if a container was deleted before the call that references said volume. To avoid this, we additionally filter the list of volumes to cleanup by any that are referenced in the target state. This means that cleanup will never remove it, as long as it's still supposed to be there, regardless of if a container references it or not. Change-type: patch Signed-off-by: Cameron Diver <cameron@balena.io>
This commit is contained in:
parent
e4caf100b5
commit
a796777967
13
src/application-manager.d.ts
vendored
13
src/application-manager.d.ts
vendored
@ -11,12 +11,15 @@ import ServiceManager from './compose/service-manager';
|
||||
import DB from './db';
|
||||
|
||||
import { APIBinder } from './api-binder';
|
||||
import { Service } from './compose/service';
|
||||
import Config from './config';
|
||||
|
||||
import NetworkManager from './compose/network-manager';
|
||||
import VolumeManager from './compose/volume-manager';
|
||||
|
||||
import Network from './compose/network';
|
||||
import Service from './compose/service';
|
||||
import Volume from './compose/volume';
|
||||
|
||||
declare interface Options {
|
||||
force?: boolean;
|
||||
running?: boolean;
|
||||
@ -65,6 +68,14 @@ export class ApplicationManager extends EventEmitter {
|
||||
// FIXME: Type this properly as it's some mutant state between
|
||||
// the state endpoint and the ApplicationManager internals
|
||||
public getStatus(): Promise<Dictionay<any>>;
|
||||
// The return type is incompleted
|
||||
public getTargetApps(): Promise<
|
||||
Dictionary<{
|
||||
services: Dictionary<Service>;
|
||||
volumes: Dictionary<Volume>;
|
||||
networks: Dictionary<Network>;
|
||||
}>
|
||||
>;
|
||||
|
||||
public serviceNameFromId(serviceId: number): Bluebird<string>;
|
||||
}
|
||||
|
@ -129,7 +129,9 @@ export class VolumeManager {
|
||||
return volume;
|
||||
}
|
||||
|
||||
public async removeOrphanedVolumes(): Promise<void> {
|
||||
public async removeOrphanedVolumes(
|
||||
referencedVolumes: string[],
|
||||
): Promise<void> {
|
||||
// Iterate through every container, and track the
|
||||
// references to a volume
|
||||
// Note that we're not just interested in containers
|
||||
@ -151,7 +153,13 @@ export class VolumeManager {
|
||||
.value();
|
||||
const volumeNames = _.map(dockerVolumes.Volumes, 'Name');
|
||||
|
||||
const volumesToRemove = _.difference(volumeNames, containerVolumes);
|
||||
const volumesToRemove = _.difference(
|
||||
volumeNames,
|
||||
containerVolumes,
|
||||
// Don't remove any volume which is still referenced
|
||||
// in the target state
|
||||
referencedVolumes,
|
||||
);
|
||||
await Promise.all(
|
||||
volumesToRemove.map(v => this.docker.getVolume(v).remove()),
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
} from '../lib/messages';
|
||||
import { doPurge, doRestart, serviceAction } from './common';
|
||||
|
||||
import Volume from '../compose/volume';
|
||||
import log from '../lib/supervisor-console';
|
||||
import supervisorVersion = require('../lib/supervisor-version');
|
||||
|
||||
@ -488,7 +489,16 @@ export function createV2Api(router: Router, applications: ApplicationManager) {
|
||||
|
||||
router.get('/v2/cleanup-volumes', async (_req, res) => {
|
||||
try {
|
||||
await applications.volumes.removeOrphanedVolumes();
|
||||
const targetState = await applications.getTargetApps();
|
||||
const referencedVolumes: string[] = [];
|
||||
_.each(targetState, app => {
|
||||
_.each(app.volumes, vol => {
|
||||
referencedVolumes.push(
|
||||
Volume.generateDockerName(vol.appId, vol.name),
|
||||
);
|
||||
});
|
||||
});
|
||||
await applications.volumes.removeOrphanedVolumes(referencedVolumes);
|
||||
res.json({
|
||||
status: 'success',
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user