feat(xo-web/pool/host): add warning if hosts don't have the same version (#7280)

Fixes #7059
This commit is contained in:
Mathieu
2024-01-18 17:13:57 +01:00
committed by GitHub
parent b7a66e9f73
commit c1c122d92c
7 changed files with 310 additions and 217 deletions
+1
View File
@@ -11,6 +11,7 @@
- [REST API] New pool action: `emergency_shutdown`, it suspends all the VMs and then shuts down all the host [#7277](https://github.com/vatesfr/xen-orchestra/issues/7277) (PR [#7279](https://github.com/vatesfr/xen-orchestra/pull/7279))
- [Tasks] Hide `/rrd_updates` tasks by default
- [Sign in] Support _Remember me_ feature with external providers (PR [#7298](https://github.com/vatesfr/xen-orchestra/pull/7298))
- [Pool/Host] Add a warning if hosts do not have the same version within a pool [#7059](https://github.com/vatesfr/xen-orchestra/issues/7059) (PR [#7280](https://github.com/vatesfr/xen-orchestra/pull/7280))
### Bug fixes
@@ -328,6 +328,7 @@ const messages = {
powerState: 'Power state',
srSharedType: 'Shared {type}',
warningHostTimeTooltip: 'Host time and XOA time are not consistent with each other',
notAllHostsHaveTheSameVersion: 'Not all hosts within {pool} have the same version',
selectExistingTags: 'Select from existing tags',
sortByDisksUsage: 'Disks usage',
+24 -1
View File
@@ -30,6 +30,7 @@ import {
createSelector,
} from 'selectors'
import { injectState } from 'reaclette'
import { Host, Pool } from 'render-xo-item'
import MiniStats from './mini-stats'
import styles from './index.css'
@@ -126,13 +127,16 @@ export default class HostItem extends Component {
message,
}
}
_getAreHostsVersionsEqual = () => this.props.state.areHostsVersionsEqualByPool[this.props.item.$pool]
_getAlerts = createSelector(
() => this.props.needsRestart,
() => this.props.item,
this._isMaintained,
() => this.state.isHostTimeConsistentWithXoaTime,
(needsRestart, host, isMaintained, isHostTimeConsistentWithXoaTime) => {
this._getAreHostsVersionsEqual,
() => this.props.state.hostsByPoolId[this.props.item.$pool],
(needsRestart, host, isMaintained, isHostTimeConsistentWithXoaTime, areHostsVersionsEqual, poolHosts) => {
const alerts = []
if (needsRestart) {
@@ -201,6 +205,25 @@ export default class HostItem extends Component {
),
})
}
if (!areHostsVersionsEqual) {
alerts.push({
level: 'danger',
render: (
<div>
<p>
<Icon icon='alarm' /> {_('notAllHostsHaveTheSameVersion', { pool: <Pool id={host.$pool} link /> })}
</p>
<ul>
{map(poolHosts, host => (
<li>{_('keyValue', { key: <Host id={host.id} />, value: host.version })}</li>
))}
</ul>
</div>
),
})
}
return alerts
}
)
+26 -1
View File
@@ -13,6 +13,7 @@ import { addTag, editPool, getHostMissingPatches, removeTag } from 'xo'
import { connectStore, formatSizeShort } from 'utils'
import { compact, flatten, map, size, uniq } from 'lodash'
import { createGetObjectsOfType, createGetHostMetrics, createSelector } from 'selectors'
import { Host, Pool } from 'render-xo-item'
import { injectState } from 'reaclette'
import styles from './index.css'
@@ -101,10 +102,15 @@ export default class PoolItem extends Component {
_getPoolLicenseInfo = () => this.props.state.poolLicenseInfoByPoolId[this.props.item.id]
_getAreHostsVersionsEqual = () => this.props.state.areHostsVersionsEqualByPool[this.props.item.id]
_getAlerts = createSelector(
() => this.props.isAdmin,
this._getPoolLicenseInfo,
(isAdmin, poolLicenseInfo) => {
this._getAreHostsVersionsEqual,
() => this.props.poolHosts,
() => this.props.item.id,
(isAdmin, poolLicenseInfo, areHostsVersionsEqual, hosts, poolId) => {
const alerts = []
if (isAdmin && this._isXcpngPool()) {
@@ -120,6 +126,25 @@ export default class PoolItem extends Component {
})
}
}
if (!areHostsVersionsEqual) {
alerts.push({
level: 'danger',
render: (
<div>
<p>
<Icon icon='alarm' /> {_('notAllHostsHaveTheSameVersion', { pool: <Pool id={poolId} link /> })}
</p>
<ul>
{map(hosts, host => (
<li>{_('keyValue', { key: <Host id={host.id} />, value: host.version })}</li>
))}
</ul>
</div>
),
})
}
return alerts
}
)
+22 -3
View File
@@ -1,6 +1,7 @@
import * as CM from 'complex-matcher'
import _ from 'intl'
import Copiable from 'copiable'
import decorate from 'apply-decorators'
import Icon from 'icon'
import map from 'lodash/map'
import React from 'react'
@@ -11,16 +12,24 @@ import { BlockLink } from 'link'
import { Container, Row, Col } from 'grid'
import { FormattedRelative } from 'react-intl'
import { formatSize, formatSizeShort, hasLicenseRestrictions } from 'utils'
import { injectState, provideState } from 'reaclette'
import Usage, { UsageElement } from 'usage'
import { getObject } from 'selectors'
import { CpuSparkLines, MemorySparkLines, NetworkSparkLines, LoadSparkLines } from 'xo-sparklines'
import { Pool } from 'render-xo-item'
import LicenseWarning from './license-warning'
export default ({ statsOverview, host, nVms, vmController, vms }) => {
export default decorate([
provideState({
computed: {
areHostsVersionsEqual: ({ areHostsVersionsEqualByPool }, { host }) => areHostsVersionsEqualByPool[host.$pool],
},
}),
injectState,
({ statsOverview, host, nVms, vmController, vms, state: { areHostsVersionsEqual } }) => {
const pool = getObject(store.getState(), host.$pool)
const vmsFilter = encodeURIComponent(new CM.Property('$container', new CM.String(host.id)).toString())
return (
<Container>
<br />
@@ -156,6 +165,16 @@ export default ({ statsOverview, host, nVms, vmController, vms }) => {
</h2>
</Col>
</Row>
{!areHostsVersionsEqual && (
<Row className='text-xs-center text-danger'>
<Col>
<p>
<Icon icon='alarm' /> {_('notAllHostsHaveTheSameVersion', { pool: <Pool id={host.$pool} link /> })}
</p>
</Col>
</Row>
)}
</Container>
)
}
},
])
+5 -1
View File
@@ -1,9 +1,11 @@
import Component from 'base-component'
import cookies from 'js-cookie'
import DocumentTitle from 'react-document-title'
import every from 'lodash/every'
import Icon from 'icon'
import Link from 'link'
import map from 'lodash/map'
import mapValues from 'lodash/mapValues'
import PropTypes from 'prop-types'
import React from 'react'
import Shortcuts from 'shortcuts'
@@ -172,7 +174,7 @@ export const ICON_POOL_LICENSE = {
xcpngLicenseById: (_, { xcpLicenses }) => keyBy(xcpLicenses, 'id'),
hostsByPoolId: createCollectionWrapper((_, { hosts }) =>
groupBy(
map(hosts, host => pick(host, ['$poolId', 'id'])),
map(hosts, host => pick(host, ['$poolId', 'id', 'version'])),
'$poolId'
)
),
@@ -230,6 +232,8 @@ export const ICON_POOL_LICENSE = {
placeholder: '',
},
isXoaStatusOk: ({ xoaStatus }) => !xoaStatus.includes('✖'),
areHostsVersionsEqualByPool: ({ hostsByPoolId }) =>
mapValues(hostsByPoolId, hosts => every(hosts, host => host.version === hosts[0].version)),
},
})
export default class XoApp extends Component {
+22 -2
View File
@@ -1,4 +1,5 @@
import _ from 'intl'
import decorate from 'apply-decorators'
import find from 'lodash/find'
import Icon from 'icon'
import map from 'lodash/map'
@@ -11,8 +12,17 @@ import { Container, Row, Col } from 'grid'
import Usage, { UsageElement } from 'usage'
import { formatSizeShort } from 'utils'
import Tooltip from 'tooltip'
import { injectState, provideState } from 'reaclette'
import { Pool } from 'render-xo-item'
export default ({ hosts, nVms, pool, srs }) => (
export default decorate([
provideState({
computed: {
areHostsVersionsEqual: ({ areHostsVersionsEqualByPool }, { pool }) => areHostsVersionsEqualByPool[pool.id],
},
}),
injectState,
({ hosts, nVms, pool, srs, state: { areHostsVersionsEqual } }) => (
<Container>
<br />
<Row className='text-xs-center'>
@@ -93,5 +103,15 @@ export default ({ hosts, nVms, pool, srs }) => (
</h2>
</Col>
</Row>
{!areHostsVersionsEqual && (
<Row className='text-xs-center text-danger'>
<Col>
<p>
<Icon icon='alarm' /> {_('notAllHostsHaveTheSameVersion', { pool: <Pool id={pool.id} link /> })}
</p>
</Col>
</Row>
)}
</Container>
)
),
])