const { Injectable } = require('flitter-di') const RoutineExecutionResult = require('./RoutineExecutionResult') const StepResult = require('./StepResult') const InvalidRoutineTypeError = require('./error/InvalidRoutineTypeError') class Routine extends Injectable { static get services() { return [...super.services, 'states', 'app'] } _config _hosts _type constructor(hosts, config, type = 'checks') { super() this.app.make(StepResult) this.app.make(RoutineExecutionResult) this._config = config this._hosts = hosts this._type = type } async execute(with_logging = false) { const result = await this._build_result() let step_no = 1 for ( const step of result.steps ) { if ( with_logging ) this.output.info('', 0) this.output.info(`(${step_no}/${result.steps.length}) ${step.step.display()}`, with_logging ? 0 : 10) step_no += 1 if ( this._type === 'checks' ) { step.status = (await step.step.check()) ? 'success' : 'fail' step.message = step.status === 'success' ? 'Check passed.' : step.step.check_message() } else if ( this._type === 'apply' ) { if ( !(await step.step.check()) ) { await step.step.apply() step.status = (await step.step.check()) ? 'success' : 'fail' step.message = step.status === 'success' ? 'State applied successfully.' : step.step.failure_message() } else { step.status = 'success' step.message = 'Check passed.' } } else { throw new InvalidRoutineTypeError(this._type) } if ( step.status === 'success' ) { this.output.success(` ${step.message}`, with_logging ? 0 : 10) } else { this.output.error(` ${step.message}`, with_logging ? 0 : 10) } } result.overall_state = result.steps.every(x => x.status === 'success') ? 'success' : 'fail' return result } async _build_result() { const steps = [] for ( const step_config of this._config.steps ) { const host = this._hosts[step_config.host] const step = this.states.from_config(host, step_config) const result = new StepResult(this, step) steps.push(result) } return new RoutineExecutionResult(steps) } } module.exports = exports = Routine