feat(xo-server, xo-web): display proxy available upgrades (#5167)

This commit is contained in:
badrAZ
2020-07-28 17:13:01 +02:00
committed by GitHub
parent 1ffef91b7a
commit 902953a1fa
6 changed files with 154 additions and 17 deletions

View File

@@ -14,6 +14,7 @@
- [Self Service] Ability to globally ignore snapshots in resource set quotas (PR [#5164](https://github.com/vatesfr/xen-orchestra/pull/5164))
- [Home/VM, host] Ability to filter by power state (PR [#5118](https://github.com/vatesfr/xen-orchestra/pull/5118))
- [Import/OVA] Allow for VMDK disks inside .ova files to be gzipped (PR [#5085](https://github.com/vatesfr/xen-orchestra/pull/5085))
- [Proxy] Show pending upgrades (PR [#5167](https://github.com/vatesfr/xen-orchestra/pull/5167))
### Bug fixes

View File

@@ -159,6 +159,17 @@ upgradeAppliance.params = {
},
}
export function getApplianceUpdaterState({ id }) {
return this.getProxyApplianceUpdaterState(id)
}
getApplianceUpdaterState.permission = 'admin'
getApplianceUpdaterState.params = {
id: {
type: 'string',
},
}
export function checkHealth({ id }) {
return this.checkProxyHealth(id)
}

View File

@@ -160,7 +160,24 @@ export default class Proxy {
'vm-data/xoa-updater-channel': JSON.stringify(this._xoProxyConf.channel),
})
return xapi.rebootVm(vmUuid)
try {
await xapi.rebootVm(vmUuid)
} catch (error) {
if (error.code !== 'VM_BAD_POWER_STATE') {
throw error
}
await xapi.startVm(vmUuid)
}
await xapi._waitObjectState(
vmUuid,
vm => extractIpFromVmNetworks(vm.$guest_metrics?.networks) !== undefined
)
}
getProxyApplianceUpdaterState(id) {
return this.callProxyMethod(id, 'appliance.updater.getState')
}
@defer
@@ -326,6 +343,8 @@ export default class Proxy {
)
await this.checkProxyHealth(proxyId)
return proxyId
}
async checkProxyHealth(id) {

View File

@@ -79,6 +79,7 @@ const messages = {
noLicenseAvailable: 'No license available',
emailPlaceholderExample: 'Email address, e.g.: it@company.net',
unknown: 'Unknown',
upgradesAvailable: 'Upgrades available',
// ----- Modals -----
alertOk: 'OK',
@@ -2371,7 +2372,6 @@ const messages = {
redeployProxyWarning: 'This action will destroy the old proxy VM',
noProxiesAvailable: 'No proxies available',
checkProxyHealth: 'Test your proxy',
upgradeProxyAppliance: 'upgrade the appliance',
proxyTestSuccess: 'Test passed for {name}',
proxyTestSuccessMessage: 'The proxy appears to work correctly',
proxyLinkedRemotes: 'Click to see linked remotes',
@@ -2382,6 +2382,7 @@ const messages = {
'The select only contains SRs connected to at least one HVM-capable host',
httpProxy: 'HTTP proxy',
httpProxyPlaceholder: 'protocol://username:password@address:port',
proxyUpgradesError: 'Unable to check upgrades availability',
// ----- Utils -----
secondsFormat: '{seconds, plural, one {# second} other {# seconds}}',

View File

@@ -3185,6 +3185,9 @@ export const destroyProxyAppliances = proxies =>
export const upgradeProxyAppliance = proxy =>
_call('proxy.upgradeAppliance', { id: resolveId(proxy) })
export const getProxyApplianceUpdaterState = id =>
_call('proxy.getApplianceUpdaterState', { id })
export const checkProxyHealth = proxy =>
_call('proxy.checkHealth', { id: resolveId(proxy) }).then(() =>
success(

View File

@@ -7,6 +7,7 @@ import NoObjects from 'no-objects'
import React from 'react'
import SortedTable from 'sorted-table'
import { adminOnly } from 'utils'
import { provideState, injectState } from 'reaclette'
import { Text } from 'editable'
import { Vm } from 'render-xo-item'
import { withRouter } from 'react-router'
@@ -15,6 +16,7 @@ import {
destroyProxyAppliances,
editProxyAppliance,
forgetProxyAppliances,
getProxyApplianceUpdaterState,
subscribeProxies,
upgradeProxyAppliance,
} from 'xo'
@@ -49,7 +51,7 @@ const ACTIONS = [
const INDIVIDUAL_ACTIONS = [
{
handler: proxy =>
handler: (proxy, { deployProxy }) =>
deployProxy({
proxy,
}),
@@ -63,13 +65,6 @@ const INDIVIDUAL_ACTIONS = [
label: _('checkProxyHealth'),
level: 'primary',
},
{
disabled: ({ vmUuid }) => vmUuid === undefined,
handler: upgradeProxyAppliance,
icon: 'vm',
label: _('upgradeProxyAppliance'),
level: 'primary',
},
{
handler: ({ id }, { router }) =>
router.push({
@@ -114,21 +109,116 @@ const COLUMNS = [
itemRenderer: proxy => <Vm id={proxy.vmUuid} link />,
name: _('vm'),
},
{
itemRenderer: (proxy, { upgradesByProxy, upgradeAppliance }) => {
const globalState = upgradesByProxy[proxy.id]
if (globalState === undefined) {
return
}
const { state } = globalState
if (state.endsWith('-upgrade-needed')) {
return (
<div>
<ActionButton
btnStyle='success'
disabled={proxy.vmUuid === undefined}
handler={upgradeAppliance}
handlerParam={proxy.id}
icon='upgrade'
>
{_('upgrade')}
</ActionButton>
<p className='text-warning'>
<Icon icon='alarm' />
&nbsp;{_('upgradesAvailable')}
</p>
</div>
)
}
if (
state === 'xoa-up-to-date' ||
state === 'xoa-upgraded' ||
state === 'updater-upgraded' ||
state === 'installer-upgraded'
) {
return (
<ActionButton
btnStyle='primary'
disabled={proxy.vmUuid === undefined}
handler={upgradeAppliance}
handlerParam={proxy.id}
icon='upgrade'
>
{_('upgrade')}
</ActionButton>
)
}
return (
<div>
<ActionButton
btnStyle='success'
disabled={proxy.vmUuid === undefined}
handler={upgradeAppliance}
handlerParam={proxy.id}
icon='upgrade'
>
{_('upgrade')}
</ActionButton>
<p className='text-danger'>
<Icon icon='alarm' />
&nbsp;{globalState.message}
</p>
</div>
)
},
name: _('upgrade'),
},
]
export default decorate([
adminOnly,
withRouter,
addSubscriptions({
proxies: subscribeProxies,
const Proxies = decorate([
provideState({
initialState: () => ({
upgradesByProxy: {},
}),
effects: {
initialize({ fetchProxyUpgrades }) {
return fetchProxyUpgrades(this.props.proxies.map(({ id }) => id))
},
async fetchProxyUpgrades(effects, proxies) {
const upgradesByProxy = { ...this.state.upgradesByProxy }
await Promise.all(
proxies.map(async id => {
upgradesByProxy[id] = await getProxyApplianceUpdaterState(id).catch(
e => ({
state: 'error',
message: _('proxyUpgradesError'),
})
)
})
)
this.state.upgradesByProxy = upgradesByProxy
},
async deployProxy({ fetchProxyUpgrades }, proxy) {
return fetchProxyUpgrades([await deployProxy(proxy)])
},
async upgradeAppliance({ fetchProxyUpgrades }, id) {
await upgradeProxyAppliance(id)
return fetchProxyUpgrades([id])
},
},
}),
({ proxies, router }) => (
withRouter,
injectState,
({ effects, proxies, router, state }) => (
<Page header={HEADER} title='proxies' formatTitle>
<div>
<div className='mt-1 mb-1'>
<ActionButton
btnStyle='success'
handler={deployProxy}
handler={effects.deployProxy}
icon='proxy'
size='large'
>
@@ -140,7 +230,10 @@ export default decorate([
collection={proxies}
columns={COLUMNS}
component={SortedTable}
data-deployProxy={effects.deployProxy}
data-router={router}
data-upgradesByProxy={state.upgradesByProxy}
data-upgradeAppliance={effects.upgradeAppliance}
emptyMessage={
<span className='text-muted'>
<Icon icon='alarm' />
@@ -155,3 +248,12 @@ export default decorate([
</Page>
),
])
export default decorate([
adminOnly,
addSubscriptions({
proxies: subscribeProxies,
}),
({ proxies }) =>
proxies === undefined ? _('statusLoading') : <Proxies proxies={proxies} />,
])