import * as Bluebird from 'bluebird'; import * as Docker from 'dockerode'; import * as _ from 'lodash'; import Config = require('./config'); import Database = require('./db'); import { checkTruthy } from './lib/validation'; import { Logger } from './logger'; /** * This class handles any special cases necessary for switching * modes in localMode. * * Currently this is needed because of inconsistencies in the way * that the state machine handles local mode and normal operation. * We should aim to remove these inconsistencies in the future. */ export class LocalModeManager { public constructor( public config: Config, public docker: Docker, public logger: Logger, public db: Database, ) { } public async init() { // Setup a listener to catch state changes relating to local mode this.config.on('change', (changed) => { if (changed.localMode != null) { const localMode = checkTruthy(changed.localMode) || false; // First switch the logger to it's correct state this.logger.switchBackend(localMode); // If we're leaving local mode, make sure to remove all of the // leftover artifacts if (!localMode) { this.removeLocalModeArtifacts(); } } }); const localMode = checkTruthy(await this.config.get('localMode') || false); if (!localMode) { // Remove any leftovers if necessary await this.removeLocalModeArtifacts(); } } public async removeLocalModeArtifacts(): Promise { try { const images = await this.getLocalModeImages(); const containers = await this.getLocalModeContainers(images); await Bluebird.map(containers, (containerId) => { console.log('Removing local mode container: ', containerId); return this.docker.getContainer(containerId).remove({ force: true }); }); await Bluebird.map(images, (imageId) => { console.log('Removing local mode image: ', imageId); return this.docker.getImage(imageId).remove({ force: true }); }); // Remove any local mode state added to the database await this.db.models('app').del().where({ source: 'local' }); } catch (e) { console.log('There was an error clearing local mode artifacts: ', e); } } private async getLocalModeImages(): Promise { // Return all local mode images present on the local docker daemon return _.map(await this.docker.listImages({ filters: { label: [ 'io.resin.local.image=1' ] } }), 'Id'); } private async getLocalModeContainers(localModeImageIds: string[]): Promise { return _(await this.docker.listContainers()) .filter(({ Image }) => _.includes(localModeImageIds, Image)) .map('Id') .value(); } } export default LocalModeManager;