feat(usage-report): include CSV raw data files to sent email (#4979)
Fixes #4970
This commit is contained in:
parent
4f8e48b7d4
commit
f9886d52da
@ -10,6 +10,7 @@
|
||||
- [VM] Move boot order setting from Disk tab to Advanced tab [#1523](https://github.com/vatesfr/xen-orchestra/issues/1523#issuecomment-563141573) (PR [#4975](https://github.com/vatesfr/xen-orchestra/pull/4975))
|
||||
- [XOA/licenses] Display proxy licenses (PR [#4944](https://github.com/vatesfr/xen-orchestra/pull/4944))
|
||||
- [Network selector] Display pool's name [#4885](https://github.com/vatesfr/xen-orchestra/issues/4885) (PR [#4990](https://github.com/vatesfr/xen-orchestra/pull/4990))
|
||||
- [Usage report] Include CSV raw data files to the sent email [#4970](https://github.com/vatesfr/xen-orchestra/issues/4970) (PR [#4979](https://github.com/vatesfr/xen-orchestra/pull/4979))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
@ -35,6 +36,7 @@
|
||||
>
|
||||
> In case of conflict, the highest (lowest in previous list) `$version` wins.
|
||||
|
||||
- xo-server-usage-report minor
|
||||
- @xen-orchestra/fs patch
|
||||
- xo-server patch
|
||||
- xo-web minor
|
||||
|
@ -38,6 +38,7 @@
|
||||
"@xen-orchestra/async-map": "^0.0.0",
|
||||
"@xen-orchestra/cron": "^1.0.6",
|
||||
"@xen-orchestra/log": "^0.2.0",
|
||||
"csv-stringify": "^5.5.0",
|
||||
"handlebars": "^4.0.6",
|
||||
"html-minifier": "^4.0.0",
|
||||
"human-format": "^0.10.0",
|
||||
|
@ -2,6 +2,7 @@ import asyncMap from '@xen-orchestra/async-map'
|
||||
import createLogger from '@xen-orchestra/log'
|
||||
import Handlebars from 'handlebars'
|
||||
import humanFormat from 'human-format'
|
||||
import stringify from 'csv-stringify'
|
||||
import { createSchedule } from '@xen-orchestra/cron'
|
||||
import { minify } from 'html-minifier'
|
||||
import {
|
||||
@ -703,6 +704,68 @@ const CRON_BY_PERIODICITY = {
|
||||
daily: '0 6 * * *',
|
||||
}
|
||||
|
||||
// let field empty in case of "NaN" and "NONE"
|
||||
const CSV_CAST = {
|
||||
number: value => (Number.isNaN(value) ? undefined : String(value)),
|
||||
string: value => (value === 'NONE' ? undefined : value),
|
||||
}
|
||||
|
||||
const CSV_COLUMNS = {
|
||||
cpu: { key: 'cpu', header: 'CPU (%)' },
|
||||
cpuEvolution: { key: 'evolution.cpu', header: 'CPU evolution (%)' },
|
||||
diskRead: { key: 'diskRead', header: 'Disk read (MiB)' },
|
||||
diskReadEvolution: {
|
||||
key: 'evolution.diskRead',
|
||||
header: 'Disk read evolution (%)',
|
||||
},
|
||||
diskWrite: { key: 'diskWrite', header: 'Disk write (MiB)' },
|
||||
diskWriteEvolution: {
|
||||
key: 'evolution.diskWrite',
|
||||
header: 'Disk write evolution (%)',
|
||||
},
|
||||
iopsRead: { key: 'iopsRead', header: 'IOPS read' },
|
||||
iopsReadEvolution: {
|
||||
key: 'evolution.iopsRead',
|
||||
header: 'IOPS read evolution (%)',
|
||||
},
|
||||
iopsTotal: { key: 'iopsTotal', header: 'IOPS total' },
|
||||
iopsTotalEvolution: {
|
||||
key: 'evolution.iopsTotal',
|
||||
header: 'IOPS total evolution (%)',
|
||||
},
|
||||
iopsWrite: { key: 'iopsWrite', header: 'IOPS write' },
|
||||
iopsWriteEvolution: {
|
||||
key: 'evolution.iopsWrite',
|
||||
header: 'IOPS write evolution (%)',
|
||||
},
|
||||
load: { key: 'load', header: 'Load average' },
|
||||
loadEvolution: {
|
||||
key: 'evolution.load',
|
||||
header: 'Load average evolution (%)',
|
||||
},
|
||||
name: { key: 'name', header: 'Name' },
|
||||
netReception: { key: 'netReception', header: 'Network RX (KiB)' },
|
||||
netReceptionEvolution: {
|
||||
key: 'evolution.netReception',
|
||||
header: 'Network RX evolution (%)',
|
||||
},
|
||||
netTransmission: { key: 'netTransmission', header: 'Network TX (KiB)' },
|
||||
netTransmissionEvolution: {
|
||||
key: 'evolution.netTransmission',
|
||||
header: 'Network TX evolution (%)',
|
||||
},
|
||||
ram: { key: 'ram', header: 'RAM (GiB)' },
|
||||
ramEvolution: { key: 'evolution.ram', header: 'RAM evolution (%)' },
|
||||
spaceFree: { key: 'freeSpace', header: 'Free space (GiB)' },
|
||||
spaceTotal: { key: 'total', header: 'Total space (GiB)' },
|
||||
spaceTotalEvolution: {
|
||||
key: 'evolution.total',
|
||||
header: 'Total space evolution (%)',
|
||||
},
|
||||
spaceUsed: { key: 'usedSpace', header: 'Used space (GiB)' },
|
||||
uuid: { key: 'uuid', header: 'UUID' },
|
||||
}
|
||||
|
||||
class UsageReportPlugin {
|
||||
constructor({ xo, getDataDir }) {
|
||||
this._xo = xo
|
||||
@ -772,6 +835,83 @@ class UsageReportPlugin {
|
||||
all: this._conf.all,
|
||||
})
|
||||
|
||||
const attachments = [
|
||||
{
|
||||
filename: `xoReport_${currDate}.html`,
|
||||
content: template(data),
|
||||
},
|
||||
]
|
||||
|
||||
if (data.allResources !== undefined) {
|
||||
attachments.push(
|
||||
{
|
||||
filename: `xoReport_${currDate}_vms.csv`,
|
||||
content: stringify(data.allResources.vms, {
|
||||
cast: CSV_CAST,
|
||||
header: true,
|
||||
columns: [
|
||||
CSV_COLUMNS.uuid,
|
||||
CSV_COLUMNS.name,
|
||||
CSV_COLUMNS.cpu,
|
||||
CSV_COLUMNS.cpuEvolution,
|
||||
CSV_COLUMNS.ram,
|
||||
CSV_COLUMNS.ramEvolution,
|
||||
CSV_COLUMNS.diskRead,
|
||||
CSV_COLUMNS.diskReadEvolution,
|
||||
CSV_COLUMNS.diskWrite,
|
||||
CSV_COLUMNS.diskWriteEvolution,
|
||||
CSV_COLUMNS.iopsRead,
|
||||
CSV_COLUMNS.iopsReadEvolution,
|
||||
CSV_COLUMNS.iopsWrite,
|
||||
CSV_COLUMNS.iopsWriteEvolution,
|
||||
CSV_COLUMNS.iopsTotal,
|
||||
CSV_COLUMNS.iopsTotalEvolution,
|
||||
CSV_COLUMNS.netReception,
|
||||
CSV_COLUMNS.netReceptionEvolution,
|
||||
CSV_COLUMNS.netTransmission,
|
||||
CSV_COLUMNS.netTransmissionEvolution,
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
filename: `xoReport_${currDate}_hosts.csv`,
|
||||
content: stringify(data.allResources.hosts, {
|
||||
cast: CSV_CAST,
|
||||
header: true,
|
||||
columns: [
|
||||
CSV_COLUMNS.uuid,
|
||||
CSV_COLUMNS.name,
|
||||
CSV_COLUMNS.cpu,
|
||||
CSV_COLUMNS.cpuEvolution,
|
||||
CSV_COLUMNS.ram,
|
||||
CSV_COLUMNS.ramEvolution,
|
||||
CSV_COLUMNS.load,
|
||||
CSV_COLUMNS.loadEvolution,
|
||||
CSV_COLUMNS.netReception,
|
||||
CSV_COLUMNS.netReceptionEvolution,
|
||||
CSV_COLUMNS.netTransmission,
|
||||
CSV_COLUMNS.netTransmissionEvolution,
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
filename: `xoReport_${currDate}_srs.csv`,
|
||||
content: stringify(data.allResources.srs, {
|
||||
cast: CSV_CAST,
|
||||
header: true,
|
||||
columns: [
|
||||
CSV_COLUMNS.uuid,
|
||||
CSV_COLUMNS.name,
|
||||
CSV_COLUMNS.spaceTotal,
|
||||
CSV_COLUMNS.spaceTotalEvolution,
|
||||
CSV_COLUMNS.spaceUsed,
|
||||
CSV_COLUMNS.spaceFree,
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
xo.sendEmail({
|
||||
to: this._conf.emails,
|
||||
@ -782,12 +922,7 @@ class UsageReportPlugin {
|
||||
Please, find the attached report.
|
||||
|
||||
best regards.`,
|
||||
attachments: [
|
||||
{
|
||||
filename: `xoReport_${currDate}.html`,
|
||||
content: template(data),
|
||||
},
|
||||
],
|
||||
attachments,
|
||||
}),
|
||||
storeData &&
|
||||
storeStats({
|
||||
|
@ -5088,6 +5088,11 @@ csv-parser@^2.1.0:
|
||||
minimist "^1.2.0"
|
||||
ndjson "^1.4.0"
|
||||
|
||||
csv-stringify@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-5.5.0.tgz#0bdeaaf60d6e15b89c752a0eceb4b4c2c8af5a8a"
|
||||
integrity sha512-G05575DSO/9vFzQxZN+Srh30cNyHk0SM0ePyiTChMD5WVt7GMTVPBQf4rtgMF6mqhNCJUPw4pN8LDe8MF9EYOA==
|
||||
|
||||
cuint@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b"
|
||||
|
Loading…
Reference in New Issue
Block a user