Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(xo-server/api/sr, xo-web/dashboard/health): list all coalesce VDIs #6120

Merged
merged 14 commits into from
Feb 25, 2022
3 changes: 3 additions & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

> Users must be able to say: “Nice enhancement, I'm eager to test it”

- [Dashboad/Health] List all existing VDIs that need coalescing. (PR [#6120](https://github.com/vatesfr/xen-orchestra/pull/6120))
julien-f marked this conversation as resolved.
Show resolved Hide resolved

### Bug fixes

> Users must be able to say: “I had this issue, happy to know it's fixed”
Expand Down Expand Up @@ -36,3 +38,4 @@
- @xen-orchestra/proxy patch
- xo-cli minor
- xo-server minor
- xo-web minor
2 changes: 2 additions & 0 deletions packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,8 @@ const messages = {
alarmObject: 'Issue on',
alarmPool: 'Pool',
spaceLeftTooltip: '{used}% used ({free} left)',
totalVdisToCoalesce: 'Total VDIs to coalesce ({total, number})',
vdisToCoalesce: 'VDIs to coalesce',

// ----- New VM -----
createVmModalTitle: 'Create VM',
Expand Down
17 changes: 17 additions & 0 deletions packages/xo-web/src/common/xo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,23 @@ export const createSrUnhealthyVdiChainsLengthSubscription = sr => {
return subscription
}

const unhealthyVdiChainsLengthBySrs = {}
export const createSrsUnhealthyVdiChainsLengthSubscription = srs =>
julien-f marked this conversation as resolved.
Show resolved Hide resolved
createSubscription(async () => {
await Promise.all(
map(srs, async sr => {
sr = resolveId(sr)
const vdiChains = await _call('sr.getUnhealthyVdiChainsLength', { sr })
julien-f marked this conversation as resolved.
Show resolved Hide resolved
if (!isEmpty(vdiChains)) {
unhealthyVdiChainsLengthBySrs[sr] = vdiChains
} else {
delete unhealthyVdiChainsLengthBySrs[sr]
}
})
)
return unhealthyVdiChainsLengthBySrs
})

// System ============================================================

export const apiMethods = _call('system.getMethodsInfo')
Expand Down
92 changes: 90 additions & 2 deletions packages/xo-web/src/xo-app/dashboard/health/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import NoObjects from 'no-objects'
import React from 'react'
import SortedTable from 'sorted-table'
import Tooltip from 'tooltip'
import { Host, Network, Pool, Sr, Vm } from 'render-xo-item'
import { Host, Network, Pool, Sr, Vdi, Vm } from 'render-xo-item'
import { SelectPool } from 'select-objects'
import { Container, Row, Col } from 'grid'
import { Card, CardHeader, CardBlock } from 'card'
import { FormattedRelative, FormattedTime } from 'react-intl'
import { countBy, filter, flatten, forEach, includes, isEmpty, map, pick } from 'lodash'
import { connectStore, formatLogs, formatSize, noop, resolveIds } from 'utils'
import { addSubscriptions, connectStore, formatLogs, formatSize, noop, resolveIds } from 'utils'
import {
createSrsUnhealthyVdiChainsLengthSubscription,
deleteMessage,
deleteMessages,
deleteOrphanedVdis,
Expand Down Expand Up @@ -501,6 +502,91 @@ const ALARM_ACTIONS = [

const HANDLED_VDI_TYPES = new Set(['system', 'user', 'ephemeral'])

const UNHEALTHY_VDI_CHAINS = [
{
itemRenderer: vdiChains => (
<div>
{vdiChains.total >= 10 && (
julien-f marked this conversation as resolved.
Show resolved Hide resolved
<span className='text-warning'>
<Icon icon='alarm' />{' '}
julien-f marked this conversation as resolved.
Show resolved Hide resolved
</span>
)}
<Sr id={vdiChains.srId} link />
</div>
),
name: _('sr'),
sortCriteria: 'name_label',
},
{
itemRenderer: vdiChains =>
map(vdiChains.vdis, (vdiDepth, id) => (
julien-f marked this conversation as resolved.
Show resolved Hide resolved
<div key={id}>
<Vdi id={id} showSize />{' '}
julien-f marked this conversation as resolved.
Show resolved Hide resolved
<span>
{_('srUnhealthyVdiDepth')}: {vdiDepth}
julien-f marked this conversation as resolved.
Show resolved Hide resolved
</span>
</div>
)),
name: _('vdisToCoalesce'),
},
]

@addSubscriptions(props => ({
unhealthyVdiChainsBySrs: createSrsUnhealthyVdiChainsLengthSubscription(props.srs),
}))
class VdiToCoalesceTable extends Component {
julien-f marked this conversation as resolved.
Show resolved Hide resolved
getVdisToCoalesceBySrs = createSelector(
() => this.props.unhealthyVdiChainsBySrs,
() => this.props.userSrs,
(unhealthyVdiChainsBySrs, srs) => {
const _unhealthyVdiChainsBySrs = {}
let total = 0
forEach(unhealthyVdiChainsBySrs, (vdiChains, srId) => {
if (!Object.keys(srs).includes(srId)) {
return
}
let totalBySrs = 0
julien-f marked this conversation as resolved.
Show resolved Hide resolved
forEach(vdiChains, vdiLength => {
totalBySrs += vdiLength
})
_unhealthyVdiChainsBySrs[srId] = {
srId,
total: totalBySrs,
vdis: vdiChains,
}
total += _unhealthyVdiChainsBySrs[srId].total
})
return {
total,
unhealthyVdiChainsBySrs: _unhealthyVdiChainsBySrs,
}
}
)

render() {
const getVdisToCoalesceBySrs = this.getVdisToCoalesceBySrs()
const { total, unhealthyVdiChainsBySrs } = getVdisToCoalesceBySrs
return (
<Row>
<Col>
<Card>
<CardHeader>
<Icon icon='disk' /> {_('totalVdisToCoalesce', { total })}
</CardHeader>
<CardBlock>
<Row className='no-default-sr'>
<Col>
<SortedTable collection={unhealthyVdiChainsBySrs} columns={UNHEALTHY_VDI_CHAINS} />
</Col>
</Row>
</CardBlock>
</Card>
</Col>
</Row>
)
}
}

@connectStore(() => {
const getSrs = createGetObjectsOfType('SR')
const getOrphanVdis = createSort(
Expand Down Expand Up @@ -557,6 +643,7 @@ const HANDLED_VDI_TYPES = new Set(['system', 'user', 'ephemeral'])
orphanVdis: getOrphanVdis,
orphanVmSnapshots: getOrphanVmSnapshots,
pools: createGetObjectsOfType('pool'),
srs: getSrs,
tooManySnapshotsVms: getTooManySnapshotsVms,
guestToolsVms: getGuestToolsVms,
userSrs: getUserSrs,
Expand Down Expand Up @@ -772,6 +859,7 @@ export default class Health extends Component {
</Col>
</Row>
)}
{props.areObjectsFetched && <VdiToCoalesceTable srs={props.srs} userSrs={userSrs} />}
<Row>
<Col>
<Card>
Expand Down