Merge remote-tracking branch 'xo-server-backup-reports/master'
This commit is contained in:
commit
56b583fc99
65
packages/xo-server-backup-reports/.editorconfig
Normal file
65
packages/xo-server-backup-reports/.editorconfig
Normal file
@ -0,0 +1,65 @@
|
||||
# http://EditorConfig.org
|
||||
#
|
||||
# Julien Fontanet's configuration
|
||||
# https://gist.github.com/julien-f/8096213
|
||||
|
||||
# Top-most EditorConfig file.
|
||||
root = true
|
||||
|
||||
# Common config.
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespaces = true
|
||||
|
||||
# CoffeeScript
|
||||
#
|
||||
# https://github.com/polarmobile/coffeescript-style-guide/blob/master/README.md
|
||||
[*.{,lit}coffee]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# Markdown
|
||||
[*.{md,mdwn,mdown,markdown}]
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
|
||||
# Package.json
|
||||
#
|
||||
# This indentation style is the one used by npm.
|
||||
[/package.json]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# Jade
|
||||
[*.jade]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# JavaScript
|
||||
#
|
||||
# Two spaces seems to be the standard most common style, at least in
|
||||
# Node.js (http://nodeguide.com/style.html#tabs-vs-spaces).
|
||||
[*.js]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# Less
|
||||
[*.less]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# Sass
|
||||
#
|
||||
# Style used for http://libsass.com
|
||||
[*.s[ac]ss]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# YAML
|
||||
#
|
||||
# Only spaces are allowed.
|
||||
[*.yaml]
|
||||
indent_size = 2
|
||||
indent_style = space
|
7
packages/xo-server-backup-reports/.gitignore
vendored
Normal file
7
packages/xo-server-backup-reports/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/dist/
|
||||
/node_modules/
|
||||
|
||||
npm-debug.log
|
||||
npm-debug.log.*
|
||||
pnpm-debug.log
|
||||
pnpm-debug.log.*
|
10
packages/xo-server-backup-reports/.npmignore
Normal file
10
packages/xo-server-backup-reports/.npmignore
Normal file
@ -0,0 +1,10 @@
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
9
packages/xo-server-backup-reports/.travis.yml
Normal file
9
packages/xo-server-backup-reports/.travis.yml
Normal file
@ -0,0 +1,9 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- stable
|
||||
- 6
|
||||
- 4
|
||||
|
||||
# Use containers.
|
||||
# http://docs.travis-ci.com/user/workers/container-based-infrastructure/
|
||||
sudo: false
|
52
packages/xo-server-backup-reports/README.md
Normal file
52
packages/xo-server-backup-reports/README.md
Normal file
@ -0,0 +1,52 @@
|
||||
# xo-server-backup-reports [](https://travis-ci.org/vatesfr/xo-server-backup-reports)
|
||||
|
||||
> Backup reports plugin for XO-Server
|
||||
|
||||
XO-Server plugin which sends email reports and Xmpp messages when backup jobs are done.
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/xo-server-backup-reports):
|
||||
|
||||
```
|
||||
> npm install --global xo-server-backup-reports
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Like all other xo-server plugins, it can be configured directly via
|
||||
the web iterface, see [the plugin documentation](https://xen-orchestra.com/docs/plugins.html).
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> npm install
|
||||
|
||||
# Run the tests
|
||||
> npm test
|
||||
|
||||
# Continuously compile
|
||||
> npm run dev
|
||||
|
||||
# Continuously run the tests
|
||||
> npm run dev-test
|
||||
|
||||
# Build for production (automatically called by npm install)
|
||||
> npm run build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are *very* welcomed, either on the documentation or on
|
||||
the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/vatesfr/xo-server-backup-reports/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
## License
|
||||
|
||||
AGPL3 © [Vates SAS](http://vates.fr)
|
91
packages/xo-server-backup-reports/package.json
Normal file
91
packages/xo-server-backup-reports/package.json
Normal file
@ -0,0 +1,91 @@
|
||||
{
|
||||
"name": "xo-server-backup-reports",
|
||||
"version": "0.6.0",
|
||||
"license": "AGPL-3.0",
|
||||
"description": "Backup reports plugin for XO-Server",
|
||||
"keywords": [
|
||||
"backup",
|
||||
"email",
|
||||
"mail",
|
||||
"orchestra",
|
||||
"plugin",
|
||||
"report",
|
||||
"reports",
|
||||
"xen",
|
||||
"xen-orchestra",
|
||||
"xo-server"
|
||||
],
|
||||
"homepage": "https://github.com/vatesfr/xo-server-backup-reports",
|
||||
"bugs": "https://github.com/vatesfr/xo-server-backup-reports/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xo-server-backup-reports"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
"email": "julien.fontanet@isonoe.net"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"main": "dist/",
|
||||
"bin": {},
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.13.1",
|
||||
"moment": "^2.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.18.0",
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-plugin-lodash": "^3.2.10",
|
||||
"babel-preset-env": "^1.0.0",
|
||||
"babel-preset-stage-0": "^6.16.0",
|
||||
"cross-env": "^3.1.3",
|
||||
"dependency-check": "^2.6.0",
|
||||
"ghooks": "^1.3.2",
|
||||
"rimraf": "^2.5.4",
|
||||
"standard": "^8.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"clean": "rimraf dist/",
|
||||
"depcheck": "dependency-check ./package.json",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"lint": "standard",
|
||||
"posttest": "npm run lint && npm run depcheck",
|
||||
"prebuild": "npm run clean",
|
||||
"predev": "npm run clean",
|
||||
"prepublish": "npm run build"
|
||||
},
|
||||
"babel": {
|
||||
"plugins": [
|
||||
"lodash"
|
||||
],
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"node": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-0"
|
||||
]
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"dist"
|
||||
],
|
||||
"parser": "babel-eslint"
|
||||
},
|
||||
"config": {
|
||||
"ghooks": {
|
||||
"commit-msg": "npm test"
|
||||
}
|
||||
}
|
||||
}
|
178
packages/xo-server-backup-reports/src/index.js
Normal file
178
packages/xo-server-backup-reports/src/index.js
Normal file
@ -0,0 +1,178 @@
|
||||
import moment from 'moment'
|
||||
import { forEach } from 'lodash'
|
||||
|
||||
export const configurationSchema = {
|
||||
type: 'object',
|
||||
|
||||
properties: {
|
||||
toMails: {
|
||||
type: 'array',
|
||||
title: 'mails',
|
||||
description: 'an array of recipients (mails)',
|
||||
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
minItems: 1
|
||||
},
|
||||
toXmpp: {
|
||||
type: 'array',
|
||||
title: 'xmpp address',
|
||||
description: 'an array of recipients (xmpp)',
|
||||
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
minItems: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const logError = e => {
|
||||
console.error('backup report error:', e)
|
||||
}
|
||||
|
||||
class BackupReportsXoPlugin {
|
||||
constructor (xo) {
|
||||
this._xo = xo
|
||||
this._report = ::this._wrapper
|
||||
}
|
||||
|
||||
configure ({ toMails, toXmpp }) {
|
||||
this._mailsReceivers = toMails
|
||||
this._xmppReceivers = toXmpp
|
||||
}
|
||||
|
||||
load () {
|
||||
this._xo.on('job:terminated', this._report)
|
||||
}
|
||||
|
||||
unload () {
|
||||
this._xo.removeListener('job:terminated', this._report)
|
||||
}
|
||||
|
||||
_wrapper (status) {
|
||||
return new Promise(resolve => resolve(this._listener(status))).catch(logError)
|
||||
}
|
||||
|
||||
_listener (status) {
|
||||
let nSuccess = 0
|
||||
let nCalls = 0
|
||||
let reportWhen
|
||||
|
||||
const text = []
|
||||
const nagiosText = []
|
||||
|
||||
forEach(status.calls, call => {
|
||||
// Ignore call if it's not a Backup a Snapshot or a Disaster Recovery.
|
||||
if (call.method !== 'vm.deltaCopy' &&
|
||||
call.method !== 'vm.rollingDeltaBackup' &&
|
||||
call.method !== 'vm.rollingDrCopy' &&
|
||||
call.method !== 'vm.rollingSnapshot' &&
|
||||
call.method !== 'vm.rollingBackup') {
|
||||
return
|
||||
}
|
||||
|
||||
reportWhen = call.params._reportWhen
|
||||
|
||||
if (reportWhen === 'never') {
|
||||
return
|
||||
}
|
||||
|
||||
nCalls++
|
||||
if (!call.error) {
|
||||
nSuccess++
|
||||
}
|
||||
|
||||
let vm
|
||||
|
||||
try {
|
||||
vm = this._xo.getObject(call.params.id || call.params.vm)
|
||||
} catch (e) {}
|
||||
|
||||
const start = moment(call.start)
|
||||
const end = moment(call.end)
|
||||
const duration = moment.duration(end - start).humanize()
|
||||
|
||||
text.push([
|
||||
`### VM : ${vm ? vm.name_label : 'undefined'}`,
|
||||
` - UUID: ${vm ? vm.uuid : 'undefined'}`,
|
||||
call.error
|
||||
? ` - Status: Failure\n - Error: ${call.error.message}`
|
||||
: ' - Status: Success',
|
||||
` - Start time: ${String(start)}`,
|
||||
` - End time: ${String(end)}`,
|
||||
` - Duration: ${duration}`
|
||||
].join('\n'))
|
||||
|
||||
if (call.error) {
|
||||
nagiosText.push(
|
||||
`[ ${vm ? vm.name_label : 'undefined'} : ${call.error.message} ]`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
// No backup calls.
|
||||
if (nCalls === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const globalSuccess = nSuccess === nCalls
|
||||
if (globalSuccess && (
|
||||
reportWhen === 'fail' || // xo-web < 5
|
||||
reportWhen === 'failure' // xo-web >= 5
|
||||
)) {
|
||||
return
|
||||
}
|
||||
|
||||
const start = moment(status.start)
|
||||
const end = moment(status.end)
|
||||
const duration = moment.duration(end - start).humanize()
|
||||
let method = status.calls[Object.keys(status.calls)[0]].method
|
||||
method = method.slice(method.indexOf('.') + 1)
|
||||
.replace(/([A-Z])/g, ' $1').replace(/^./, letter => letter.toUpperCase()) // humanize
|
||||
const tag = status.calls[Object.keys(status.calls)[0]].params.tag
|
||||
|
||||
// Global status.
|
||||
text.unshift([
|
||||
`## Global status for "${tag}" (${method}): ${globalSuccess ? 'Success' : 'Fail'}`,
|
||||
` - Start time: ${String(start)}`,
|
||||
` - End time: ${String(end)}`,
|
||||
` - Duration: ${duration}`,
|
||||
` - Successful backed up VM number: ${nSuccess}`,
|
||||
` - Failed backed up VM: ${nCalls - nSuccess}`,
|
||||
''
|
||||
].join('\n'))
|
||||
|
||||
const markdown = text.join('\n')
|
||||
const markdownNagios = nagiosText.join(' ')
|
||||
|
||||
// TODO : Handle errors when `sendEmail` isn't present. (Plugin dependencies)
|
||||
|
||||
const xo = this._xo
|
||||
return Promise.all([
|
||||
xo.sendEmail && xo.sendEmail({
|
||||
to: this._mailsReceivers,
|
||||
subject: `[Xen Orchestra][${globalSuccess ? 'Success' : 'Failure'}] Backup report for ${tag}`,
|
||||
markdown
|
||||
}),
|
||||
xo.sendToXmppClient && xo.sendToXmppClient({
|
||||
to: this._xmppReceivers,
|
||||
message: markdown
|
||||
}),
|
||||
xo.sendSlackMessage && xo.sendSlackMessage({
|
||||
message: markdown
|
||||
}),
|
||||
xo.sendPassiveCheck && xo.sendPassiveCheck({
|
||||
status: globalSuccess ? 0 : 2,
|
||||
message: globalSuccess ? `[Xen Orchestra] [Success] Backup report for ${tag}` : `[Xen Orchestra] [Failure] Backup report for ${tag} - VMs : ${markdownNagios}`
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
export default ({ xo }) => new BackupReportsXoPlugin(xo)
|
Loading…
Reference in New Issue
Block a user