Skip to content

Commit

Permalink
feat(xo-server/api/sr, xo-web/dashboard/health): list coalescing VDIs (
Browse files Browse the repository at this point in the history
…#6120)

See zammad#5224
  • Loading branch information
MathieuRA authored Feb 25, 2022
1 parent 6e6886a commit 0975863
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

> Users must be able to say: “Nice enhancement, I'm eager to test it”
- [Dashboad/Health] List all VDIs that need coalescing (PR [#6120](https://github.com/vatesfr/xen-orchestra/pull/6120))
- [Menu] Show a warning icon when some SRs have more than 10 VDIs to coalesce (PR [#6120](https://github.com/vatesfr/xen-orchestra/pull/6120))

### Bug fixes

> Users must be able to say: “I had this issue, happy to know it's fixed”
Expand Down
11 changes: 11 additions & 0 deletions packages/xo-server/src/api/sr.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncMapSettled from '@xen-orchestra/async-map/legacy.js'
import filter from 'lodash/filter.js'
import some from 'lodash/some.js'

import ensureArray from '../_ensureArray.mjs'
Expand Down Expand Up @@ -864,6 +865,16 @@ probeNfsExists.resolve = {

// -------------------------------------------------------------------

export function getAllUnhealthyVdiChainsLength() {
const unhealthyVdiChainsLengthBySr = {}
filter(this.objects.all, obj => obj.type === 'SR' && obj.content_type !== 'iso' && obj.size > 0).forEach(sr => {
unhealthyVdiChainsLengthBySr[sr.uuid] = this.getXapi(sr).getUnhealthyVdiChainsLength(sr)
})
return unhealthyVdiChainsLengthBySr
}

// -------------------------------------------------------------------

export function getUnhealthyVdiChainsLength({ sr }) {
return this.getXapi(sr).getUnhealthyVdiChainsLength(sr)
}
Expand Down
4 changes: 4 additions & 0 deletions packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ const messages = {
homeMissingPatches: 'Missing patches',
homePoolMaster: 'Master:',
homeResourceSet: 'Resource set: {resourceSet}',
homeSrVdisToCoalesce: 'Some VDIs need to be coalesced',
highAvailability: 'High Availability',
powerState: 'Power state',
srSharedType: 'Shared {type}',
Expand Down Expand Up @@ -1385,6 +1386,7 @@ const messages = {
metricsLoading: 'Loading…',

// ----- Health -----
length: 'Length: {length}',
deleteBackups: 'Delete backup{nBackups, plural, one {} other {s}}',
deleteBackupsMessage:
'Are you sure you want to delete {nBackups, number} backup{nBackups, plural, one {} other {s}}?',
Expand Down Expand Up @@ -1432,6 +1434,8 @@ const messages = {
alarmObject: 'Issue on',
alarmPool: 'Pool',
spaceLeftTooltip: '{used}% used ({free} left)',
vdisToCoalesce: 'VDIs to coalesce',
srVdisToCoalesceWarning: 'This SR has more than {limitVdis, number} VDIs to coalesce',

// ----- New VM -----
createVmModalTitle: 'Create VM',
Expand Down
3 changes: 3 additions & 0 deletions packages/xo-web/src/common/xo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import parseNdJson from './_parseNdJson'
// ===================================================================

export const ITEMS_PER_PAGE_OPTIONS = [10, 20, 50, 100]
export const VDIS_TO_COALESCE_LIMIT = 10

// ===================================================================

Expand Down Expand Up @@ -524,6 +525,8 @@ subscribeVolumeInfo.forceRefresh = (() => {
}
})()

export const subscribeSrsUnhealthyVdiChainsLength = createSubscription(() => _call('sr.getAllUnhealthyVdiChainsLength'))

const unhealthyVdiChainsLengthSubscriptionsBySr = {}
export const createSrUnhealthyVdiChainsLengthSubscription = sr => {
sr = resolveId(sr)
Expand Down
3 changes: 3 additions & 0 deletions packages/xo-web/src/xo-app/dashboard/health/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
createSort,
} from 'selectors'

import UnhealthyVdis from './unhealthyVdis'

const SrColContainer = connectStore(() => ({
container: createGetObject(),
}))(
Expand Down Expand Up @@ -772,6 +774,7 @@ export default class Health extends Component {
</Col>
</Row>
)}
{props.areObjectsFetched && <UnhealthyVdis />}
<Row>
<Col>
<Card>
Expand Down
87 changes: 87 additions & 0 deletions packages/xo-web/src/xo-app/dashboard/health/unhealthyVdis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import _ from 'intl'
import addSubscriptions from 'add-subscriptions'
import decorate from 'apply-decorators'
import Icon from 'icon'
import React from 'react'
import SingleLineRow from 'single-line-row'
import SortedTable from 'sorted-table'
import Tooltip from 'tooltip'
import { Card, CardHeader, CardBlock } from 'card'
import { Col, Row } from 'grid'
import { injectState, provideState } from 'reaclette'
import { map, size } from 'lodash'
import { Sr, Vdi } from 'render-xo-item'
import { subscribeSrsUnhealthyVdiChainsLength, VDIS_TO_COALESCE_LIMIT } from 'xo'

const COLUMNS = [
{
itemRenderer: (srId, { unhealthyVdiChainsLengthBySr }) => (
<div>
<Sr id={srId} link />{' '}
{size(unhealthyVdiChainsLengthBySr[srId]) >= VDIS_TO_COALESCE_LIMIT && (
<Tooltip content={_('srVdisToCoalesceWarning', { limitVdis: VDIS_TO_COALESCE_LIMIT })}>
<span className='text-warning'>
<Icon icon='alarm' />
</span>
</Tooltip>
)}
</div>
),
name: _('sr'),
sortCriteria: 'name_label',
},
{
itemRenderer: (srId, { unhealthyVdiChainsLengthBySr }) => (
<div>
{map(unhealthyVdiChainsLengthBySr[srId], (chainLength, vdiId) => (
<SingleLineRow key={vdiId}>
<Col>
<Vdi id={vdiId} />
</Col>
<Col>
<span>{_('length', { length: chainLength })}</span>
</Col>
</SingleLineRow>
))}
</div>
),
name: _('vdisToCoalesce'),
},
]

const UnhealthyVdis = decorate([
addSubscriptions({
unhealthyVdiChainsLengthBySr: subscribeSrsUnhealthyVdiChainsLength,
}),
provideState({
computed: {
srIds: (state, { unhealthyVdiChainsLengthBySr = {} }) => Object.keys(unhealthyVdiChainsLengthBySr),
},
}),
injectState,
({ state: { srIds }, unhealthyVdiChainsLengthBySr }) => (
<Row>
<Col>
<Card>
<CardHeader>
<Icon icon='disk' /> {_('vdisToCoalesce')}
</CardHeader>
<CardBlock>
<Row>
<Col>
<SortedTable
data-unhealthyVdiChainsLengthBySr={unhealthyVdiChainsLengthBySr}
collection={srIds}
columns={COLUMNS}
stateUrlParam='s_vdis_to_coalesce'
/>
</Col>
</Row>
</CardBlock>
</Card>
</Col>
</Row>
),
])

export default UnhealthyVdis
21 changes: 20 additions & 1 deletion packages/xo-web/src/xo-app/menu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
subscribeProxies,
subscribeProxiesApplianceUpdaterState,
subscribeResourceSets,
subscribeSrsUnhealthyVdiChainsLength,
VDIS_TO_COALESCE_LIMIT,
} from 'xo'
import {
createFilter,
Expand All @@ -29,7 +31,7 @@ import {
getXoaState,
isAdmin,
} from 'selectors'
import { every, forEach, identity, isEmpty, isEqual, map, pick, some } from 'lodash'
import { every, forEach, identity, isEmpty, isEqual, map, pick, size, some } from 'lodash'

import styles from './index.css'

Expand Down Expand Up @@ -67,6 +69,7 @@ const returnTrue = () => true
cb(map(proxies, 'id').sort())
}),
resourceSets: subscribeResourceSets,
unhealthyVdiChainsLength: subscribeSrsUnhealthyVdiChainsLength,
})
@injectState
export default class Menu extends Component {
Expand Down Expand Up @@ -135,6 +138,12 @@ export default class Menu extends Component {
missingPatches => some(missingPatches, _ => _)
)

_hasUnhealthyVdis = createSelector(
() => this.state.unhealthyVdiChainsLength,
unhealthyVdiChainsLength =>
some(unhealthyVdiChainsLength, vdiChainsLength => size(vdiChainsLength) >= VDIS_TO_COALESCE_LIMIT)
)

_toggleCollapsed = event => {
event.preventDefault()
this._removeListener()
Expand Down Expand Up @@ -211,6 +220,14 @@ export default class Menu extends Component {
</Tooltip>
) : null

const unhealthyVdisWarning = this._hasUnhealthyVdis() ? (
<Tooltip content={_('homeUnhealthyVdis')}>
<span className='text-warning'>
<Icon icon='alarm' />
</span>
</Tooltip>
) : null

/* eslint-disable object-property-newline */
const items = [
{
Expand Down Expand Up @@ -247,6 +264,7 @@ export default class Menu extends Component {
to: '/dashboard/overview',
icon: 'menu-dashboard',
label: 'dashboardPage',
extra: [unhealthyVdisWarning],
subMenu: [
{
to: '/dashboard/overview',
Expand All @@ -267,6 +285,7 @@ export default class Menu extends Component {
to: '/dashboard/health',
icon: 'menu-dashboard-health',
label: 'overviewHealthDashboardPage',
extra: [unhealthyVdisWarning],
},
],
},
Expand Down

0 comments on commit 0975863

Please sign in to comment.