feat(xo-web/proxy): register an existing proxy (#6556)

This commit is contained in:
Mathieu
2022-11-29 05:44:51 -08:00
committed by GitHub
parent ed34d9cbc0
commit 552a9c7b9f
5 changed files with 124 additions and 2 deletions

View File

@@ -11,6 +11,7 @@
- [OVA export] Speed up OVA generation by 2. Generated file will be bigger (as big as uncompressed XVA) (PR [#6487](https://github.com/vatesfr/xen-orchestra/pull/6487))
- [Settings/Users] Add `Remove` button to delete OTP of users from the admin panel [Forum#6521](https://xcp-ng.org/forum/topic/6521/remove-totp-on-a-user-account) (PR [#6541](https://github.com/vatesfr/xen-orchestra/pull/6541))
- [Plugin/transport-nagios] XO now reports backed up VMs invidually with the VM name label used as _host_ and backup job name used as _service_
- [Proxies] Ability to register an existing proxy (PR [#6556](https://github.com/vatesfr/xen-orchestra/pull/6556))
### Bug fixes

View File

@@ -110,6 +110,7 @@ const messages = {
addCustomField: 'Add custom field',
editCustomField: 'Edit custom field',
deleteCustomField: 'Delete custom field',
onlyAvailableXoaUsers: 'Only available to XOA users',
// ----- Modals -----
alertOk: 'OK',
@@ -1332,6 +1333,7 @@ const messages = {
vmCoresPerSocketExceedsSocketsLimit: 'The selected value exceeds the sockets limit ({maxSockets, number})',
vmHaDisabled: 'Disabled',
vmMemoryLimitsLabel: 'Memory limits (min/max)',
vmUuid: 'VM UUID',
vmVgpu: 'vGPU',
vmVgpus: 'GPUs',
vmVgpuNone: 'None',
@@ -2471,7 +2473,6 @@ const messages = {
proxyUnknownVm: 'Unknown proxy VM.',
// ----- proxies -----
deployProxyDisabled: 'Only available to XOA users',
forgetProxyApplianceTitle: 'Forget prox{n, plural, one {y} other {ies}}',
forgetProxyApplianceMessage: 'Are you sure you want to forget {n, number} prox{n, plural, one {y} other {ies}}?',
forgetProxies: 'Forget proxy(ies)',
@@ -2482,11 +2483,16 @@ const messages = {
redeployProxy: 'Redeploy proxy',
redeployProxyAction: 'Redeploy this proxy',
redeployProxyWarning: 'This action will destroy the old proxy VM',
registerProxy: 'Register a proxy',
noProxiesAvailable: 'No proxies available',
checkProxyHealth: 'Test your proxy',
updateProxyApplianceSettings: 'Update appliance settings',
urlNotFound: 'URL not found',
proxyAuthToken: 'Authentication token',
proxyConnectionFailedAfterRegistrationMessage: 'Unable to connect to this proxy. Do you want to forget it?',
proxyCopyUrl: 'Copy proxy URL',
proxyError: 'Proxy error',
proxyOptionalVmUuid: 'VM UUID is optional but recommended.',
proxyTestSuccess: 'Test passed for {name}',
proxyTestSuccessMessage: 'The proxy appears to work correctly',
proxyTestFailed: 'Test failed for {name}',
@@ -2505,6 +2511,7 @@ const messages = {
'The upgrade will interrupt {nJobs, number} running backup job{nJobs, plural, one {} other {s}}. Do you want to continue?',
proxiesNeedUpgrade: 'Some proxies need to be upgraded.',
upgradeNeededForProxies: 'Some proxies need to be upgraded. Click here to get more information.',
xoProxyConcreteGuide: 'XO Proxy: a concrete guide',
// ----- Utils -----
secondsFormat: '{seconds, plural, one {# second} other {# seconds}}',

View File

@@ -26,6 +26,7 @@ import invoke from '../invoke'
import Icon from '../icon'
import logError from '../log-error'
import NewAuthTokenModal from './new-auth-token-modal'
import RegisterProxyModal from './register-proxy-modal'
import renderXoItem, { renderXoItemFromId, Vm } from '../render-xo-item'
import store from 'store'
import { alert, chooseAction, confirm } from '../modal'
@@ -3306,6 +3307,37 @@ export const deployProxyAppliance = (license, sr, { network, proxy, ...props } =
...props,
})::tap(subscribeProxies.forceRefresh)
export const registerProxy = async () => {
const getStringOrUndefined = string => (string.trim() === '' ? undefined : string)
const { address, authenticationToken, name, vmUuid } = await confirm({
body: <RegisterProxyModal />,
icon: 'connect',
title: _('registerProxy'),
})
const proxyId = await registerProxyApplicance({
address: getStringOrUndefined(address),
authenticationToken: getStringOrUndefined(authenticationToken),
name: getStringOrUndefined(name),
vmUuid: getStringOrUndefined(vmUuid),
})
const _isProxyWorking = await isProxyWorking(proxyId).catch(err => {
console.error('isProxyWorking error:', err)
return false
})
if (!_isProxyWorking) {
await confirm({
body: _('proxyConnectionFailedAfterRegistrationMessage'),
title: _('proxyError'),
})
await forgetProxyAppliances([proxyId])
}
}
export const registerProxyApplicance = proxyInfo =>
_call('proxy.register', proxyInfo)::tap(subscribeProxies.forceRefresh)
export const editProxyAppliance = (proxy, { vm, ...props }) =>
_call('proxy.update', {
id: resolveId(proxy),
@@ -3365,6 +3397,8 @@ export const checkProxyHealth = async proxy => {
)
}
export const isProxyWorking = async proxy => (await _call('proxy.checkHealth', { id: resolveId(proxy) })).success
// Audit plugin ---------------------------------------------------------
const METHOD_NOT_FOUND_CODE = -32601

View File

@@ -0,0 +1,68 @@
import _ from 'intl'
import Component from 'base-component'
import Icon from 'icon'
import React from 'react'
import SingleLineRow from 'single-line-row'
import { Col, Container } from 'grid'
import { Input as DebounceInput } from 'debounce-input-decorator'
export default class RegisterProxyModal extends Component {
state = {
address: '',
authenticationToken: '',
name: '',
vmUuid: '',
}
get value() {
return this.state
}
render() {
const { address, authenticationToken, name, vmUuid } = this.state
return (
<Container>
<a href='https://xen-orchestra.com/blog/xo-proxy-a-concrete-guide/' rel='noopener noreferrer'>
<Icon icon='info' /> {_('xoProxyConcreteGuide')}
</a>
<SingleLineRow className='mt-1'>
<Col size={6}>{_('proxyAuthToken')}</Col>
<Col size={6}>
<DebounceInput
className='form-control'
onChange={this.linkState('authenticationToken')}
value={authenticationToken}
/>
</Col>
</SingleLineRow>
<SingleLineRow className='mt-1'>
<Col size={6}>{_('name')}</Col>
<Col size={6}>
<DebounceInput className='form-control' onChange={this.linkState('name')} value={name} />
</Col>
</SingleLineRow>
<SingleLineRow className='mt-1'>
<Col size={6}>{_('address')}</Col>
<Col size={6}>
<DebounceInput
className='form-control'
onChange={this.linkState('address')}
placeholder='192.168.2.20[:4343]'
value={address}
/>
</Col>
</SingleLineRow>
<SingleLineRow className='mt-1'>
<Col size={6}>{_('vmUuid')}</Col>
<Col size={6}>
<DebounceInput className='form-control' onChange={this.linkState('vmUuid')} value={vmUuid} />
</Col>
</SingleLineRow>
<SingleLineRow className='mt-1'>
<Col className='text-info'>
<Icon icon='info' /> {_('proxyOptionalVmUuid')}
</Col>
</SingleLineRow>
</Container>
)
}
}

View File

@@ -23,6 +23,7 @@ import {
forgetProxyAppliances,
getLicenses,
getProxyApplianceUpdaterState,
registerProxy,
subscribeProxies,
upgradeProxyAppliance,
EXPIRES_SOON_DELAY,
@@ -322,10 +323,21 @@ const Proxies = decorate([
handler={effects.deployProxy}
icon='proxy'
size='large'
tooltip={state.isFromSource ? _('deployProxyDisabled') : undefined}
tooltip={state.isFromSource ? _('onlyAvailableXoaUsers') : undefined}
>
{_('deployProxy')}
</ActionButton>
<ActionButton
className='ml-1'
btnStyle='success'
disabled={state.isFromSource}
handler={registerProxy}
icon='connect'
size='large'
tooltip={state.isFromSource ? _('onlyAvailableXoaUsers') : undefined}
>
{_('registerProxy')}
</ActionButton>
</div>
<NoObjects
actions={ACTIONS}