Additional Fix¶
A fix is used as addition to tests. They are added to the test instance on case of a problem (error or warning).
Then after the test was done the following steps are possible:
-
Analyze
The analyzation will take place directly after a test has finished. It should create a description explaining the values from the test and interpreting it's meaning and what to do to optimize this.
-
Repair
If the findings from the analyzation can be solved by automatic repair this method will do it.
Environment¶
this.test
- test instance to which the fix belongs tothis.data
- fix data from configurationthis.lang
- language to use in descriptionsthis.context
- context data to be usedthis.debug
- debug logger
Methods to Implement¶
async this.analyze ()
async this.repair ()
Result Elements¶
this.type
:manual
- only show description, user has to fix manualauto
- automatic repair is possible
this.title
- title of fixthis.description
- long descriptive textthis.action
- action taken in repairthis.status
:MANUAL
- manual testNODATA
- could not analyzeIRRELEVANT
- nothing to be doneOK
- repair successfulERROR
- repair failed
this.error
- error message on repair problemthis._log
- Output log list. Each line should start with the verbosity level followed by colon.
Log Helper¶
Each of the following log helper will do the same, add the element to the this._log
element with the correct verbose level:
this.logFix (msg: string, log: boolean = true)
this.logProcess (msg: any, log: boolean = true)
this.logStdout (msg: string, log: boolean = true)
this.logStderr (msg: string, log: boolean = true)
this.logCode (msg: number, log: boolean = true)
Execution Helper¶
First the shell execution is integrated with handy functions:
this.shell (fn: () => Promise<any>)
this.execute (cmd: string, log: boolean = true): Promise<any>
this.commands (list: string[], sudo = false)
And then other (sub) tests can be made as further analyzation. So if in example a service won't work check the tcp port and ping if there is a network problem;
this.subTest (setup: any): Promise<any>
this.subTests (setup: any[], analyze = false): Promise<any[]>
Basic Structure¶
import Fix from '.'
import { T } from '../i18n';
class FixXxx extends Fix {
public async analyze () {
const t = T(this.lang, 'linux')
this.title = t('os.fix.title')
// WRITE description
// SET status
}
// only if repair is implemented
public async repair () {
const t = T(this.lang, 'linux')
this.action = t('os.fix.repair') + '\n'
// REPAIR
// SET status, error
}
}
export default FixLinuxOS
Full Example¶
import * as Builder from '@alinex/validator/lib/schema';
import { inspect } from 'util'
import FixLinux from '.'
import { T } from '../../i18n';
//import { indent } from '../../string';
class FixLinuxOS extends FixLinux {
public async analyze () {
const t = T(this.lang, 'linux')
this.title = t('os.fix.title')
this.debug('analyze')
// mongodb test
const result = this.test.result
let msg = ''
if (result.security) msg += t('os.fix.security', { count: result.security }) + '\n'
if (result.updates) msg += t('os.fix.updates', { count: result.updates }) + '\n'
if (result.removes) msg += t('os.fix.removes', { count: result.removes }) + '\n'
if (msg) {
this.type = 'auto'
if (result.distBase === 'debian') msg += t('os.fix.upgradeDebian')
if (result.distBase === 'arch') msg += t('os.fix.upgradeArch')
}
if (msg) {
this.description += msg
this.status = 'MANUAL'
} else this.status = 'IRRELEVANT'
}
public async repair () {
const t = T(this.lang, 'linux')
this.action = t('os.fix.repair') + '\n'
this.debug('repair')
const result = this.test.result
await this.shell(async () => {
// commands
let cmds = await this.commands(['apt', 'shutdown'], true)
const nosudo = Object.keys(cmds).filter(e => !cmds[e]).map(e => inspect(e.substr(1)))
if (nosudo.join()) {
this.status = 'NODATA'
this.error = new Error(t('core:fix.nosudoRepair', { count: nosudo.length, cmd: nosudo.join(', ') }))
return
}
if (result.updates || result.removes) {
await this.execute(`${cmds.$apt} upgrade -y`)
.then(res => {
if (res.exitCode) throw new Error(`Failed upgrade with status code ${res.exitCode}.`)
else this.status = 'OK'
})
await this.execute(`${cmds.$apt} autoremove --purge -y`)
.then(res => {
if (res.exitCode) throw new Error(`Failed autoremove with status code ${res.exitCode}.`)
else this.status = 'OK'
})
}
// reboot
await this.execute(`test -e /var/run/reboot-required && ${cmds.$shutdown} -r now`)
.then(res => {
if (res.exitCode) throw new Error(`Failed to reboot system code: ${res.exitCode}.`)
else this.status = 'OK'
})
})
// general error
.catch((e: Error) => {
this.status = 'ERROR'
this.error = e
})
}
}
export default FixLinuxOS