feat(xo-web/health): list VM snapshots related to non-existing backup jobs (#2899)
Fixes #2828
This commit is contained in:
parent
9c05a59b5f
commit
da4ff3082d
@ -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',
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user