feat(xo-web/proxy): register an existing proxy (#6556)
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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}}',
|
||||
|
||||
@@ -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
|
||||
|
||||
68
packages/xo-web/src/common/xo/register-proxy-modal/index.js
Normal file
68
packages/xo-web/src/common/xo/register-proxy-modal/index.js
Normal 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>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user