feat(xo-web/health): list VM snapshots related to non-existing backup jobs (#2899)

Fixes #2828
This commit is contained in:
Rajaa.BARHTAOUI 2018-05-04 15:59:11 +02:00 committed by Pierre Donias
parent 9c05a59b5f
commit da4ff3082d
2 changed files with 51 additions and 6 deletions

View File

@ -1038,6 +1038,8 @@ const messages = {
vmNameLabel: 'Name', vmNameLabel: 'Name',
vmNameDescription: 'Description', vmNameDescription: 'Description',
vmContainer: 'Resident on', vmContainer: 'Resident on',
vmSnapshotsRelatedToNonExistentBackups:
'VM snapshots related to non-existent backups',
alarmMessage: 'Alarms', alarmMessage: 'Alarms',
noAlarms: 'No alarms', noAlarms: 'No alarms',
alarmDate: 'Date', alarmDate: 'Date',

View File

@ -10,14 +10,20 @@ import TabButton from 'tab-button'
import Tooltip from 'tooltip' import Tooltip from 'tooltip'
import Upgrade from 'xoa-upgrade' import Upgrade from 'xoa-upgrade'
import xml2js from 'xml2js' import xml2js from 'xml2js'
import { Card, CardHeader, CardBlock } from 'card'
import { confirm } from 'modal' import { confirm } from 'modal'
import { connectStore, formatSize, noop, resolveIds } from 'utils'
import { Container, Row, Col } from 'grid'
import { flatten, get, includes, isEmpty, map, mapValues } from 'lodash'
import { FormattedRelative, FormattedTime } from 'react-intl'
import { fromCallback } from 'promise-toolbox'
import { SelectPool } from 'select-objects' import { SelectPool } from 'select-objects'
import { fromCallback } from 'promise-toolbox'
import { Container, Row, Col } from 'grid'
import { Card, CardHeader, CardBlock } from 'card'
import { FormattedRelative, FormattedTime } from 'react-intl'
import { flatten, get, includes, isEmpty, map, mapValues } from 'lodash'
import {
addSubscriptions,
connectStore,
formatSize,
noop,
resolveIds,
} from 'utils'
import { import {
deleteMessage, deleteMessage,
deleteOrphanedVdis, deleteOrphanedVdis,
@ -26,6 +32,7 @@ import {
deleteVdi, deleteVdi,
deleteVm, deleteVm,
isSrWritable, isSrWritable,
subscribeSchedules,
} from 'xo' } from 'xo'
import { import {
areObjectsFetched, areObjectsFetched,
@ -383,6 +390,9 @@ const ALARM_COLUMNS = [
}, },
] ]
@addSubscriptions({
schedules: subscribeSchedules,
})
@connectStore(() => { @connectStore(() => {
const getOrphanVdiSnapshots = createGetObjectsOfType('VDI-snapshot') const getOrphanVdiSnapshots = createGetObjectsOfType('VDI-snapshot')
.filter([_ => !_.$snapshot_of && _.$VBDs.length === 0]) .filter([_ => !_.$snapshot_of && _.$VBDs.length === 0])
@ -390,6 +400,15 @@ const ALARM_COLUMNS = [
const getOrphanVmSnapshots = createGetObjectsOfType('VM-snapshot') const getOrphanVmSnapshots = createGetObjectsOfType('VM-snapshot')
.filter([snapshot => !snapshot.$snapshot_of]) .filter([snapshot => !snapshot.$snapshot_of])
.sort() .sort()
const getLoneBackupSnapshots = createGetObjectsOfType('VM-snapshot').filter(
createSelector(
createCollectionWrapper((_, props) => map(props.schedules, 'id')),
scheduleIds => _ => {
const scheduleId = _.other['xo:backup:schedule']
return scheduleId !== undefined && !includes(scheduleIds, scheduleId)
}
)
)
const getUserSrs = createGetObjectsOfType('SR').filter([isSrWritable]) const getUserSrs = createGetObjectsOfType('SR').filter([isSrWritable])
const getVdiSrs = createGetObjectsOfType('SR').pick( const getVdiSrs = createGetObjectsOfType('SR').pick(
createSelector(getOrphanVdiSnapshots, snapshots => map(snapshots, '$SR')) createSelector(getOrphanVdiSnapshots, snapshots => map(snapshots, '$SR'))
@ -405,6 +424,7 @@ const ALARM_COLUMNS = [
vdiOrphaned: getOrphanVdiSnapshots, vdiOrphaned: getOrphanVdiSnapshots,
vdiSr: getVdiSrs, vdiSr: getVdiSrs,
vmOrphaned: getOrphanVmSnapshots, vmOrphaned: getOrphanVmSnapshots,
vmBackupSnapshots: getLoneBackupSnapshots,
} }
}) })
export default class Health extends Component { export default class Health extends Component {
@ -490,6 +510,11 @@ export default class Health extends Component {
this._getPoolPredicate this._getPoolPredicate
) )
_getVmBackupSnapshots = createFilter(
() => this.props.vmBackupSnapshots,
this._getPoolPredicate
)
_getAlertMessages = createFilter( _getAlertMessages = createFilter(
() => this.props.alertMessages, () => this.props.alertMessages,
this._getPoolPredicate this._getPoolPredicate
@ -610,6 +635,24 @@ export default class Health extends Component {
</Card> </Card>
</Col> </Col>
</Row> </Row>
<Row className='snapshot-vms'>
<Col>
<Card>
<CardHeader>
<Icon icon='vm' /> {_('vmSnapshotsRelatedToNonExistentBackups')}
</CardHeader>
<CardBlock>
<NoObjects
collection={this._getVmBackupSnapshots()}
columns={VM_COLUMNS}
component={SortedTable}
emptyMessage={_('noSnapshots')}
shortcutsTarget='.snapshot-vms'
/>
</CardBlock>
</Card>
</Col>
</Row>
<Row> <Row>
<Col> <Col>
<Card> <Card>