Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 13 commits into from
Nov 29, 2022
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

- [Remotes] Prevent remote path from ending with `xo-vm-backups` as it's usually a mistake
- [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))
- [Proxies] Ability to register an existing proxy (PR [#6556](https://github.com/vatesfr/xen-orchestra/pull/6556))

### Bug fixes

Expand Down
9 changes: 8 additions & 1 deletion packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const messages = {
addCustomField: 'Add custom field',
editCustomField: 'Edit custom field',
deleteCustomField: 'Delete custom field',
onlyAvailableXoaUsers: 'Only available to XOA users',
pdonias marked this conversation as resolved.
Show resolved Hide resolved

// ----- Modals -----
alertOk: 'OK',
Expand Down Expand Up @@ -1331,6 +1332,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',
Expand Down Expand Up @@ -2470,7 +2472,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)',
Expand All @@ -2481,11 +2482,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}',
Expand All @@ -2504,6 +2510,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',
Rajaa-BARHTAOUI marked this conversation as resolved.
Show resolved Hide resolved

// ----- Utils -----
secondsFormat: '{seconds, plural, one {# second} other {# seconds}}',
Expand Down
34 changes: 34 additions & 0 deletions packages/xo-web/src/common/xo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -3303,6 +3304,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'),
Rajaa-BARHTAOUI marked this conversation as resolved.
Show resolved Hide resolved
})

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),
Expand Down Expand Up @@ -3362,6 +3394,8 @@ export const checkProxyHealth = async proxy => {
)
}

export const isProxyWorking = async proxy => (await _call('proxy.checkHealth', { id: resolveId(proxy) })).success
Rajaa-BARHTAOUI marked this conversation as resolved.
Show resolved Hide resolved

// Audit plugin ---------------------------------------------------------

const METHOD_NOT_FOUND_CODE = -32601
Expand Down
68 changes: 68 additions & 0 deletions packages/xo-web/src/common/xo/register-proxy-modal/index.js
Original file line number Diff line number Diff line change
@@ -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>
julien-f marked this conversation as resolved.
Show resolved Hide resolved
<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}
julien-f marked this conversation as resolved.
Show resolved Hide resolved
/>
</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>
)
}
}
14 changes: 13 additions & 1 deletion packages/xo-web/src/xo-app/proxies/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
forgetProxyAppliances,
getLicenses,
getProxyApplianceUpdaterState,
registerProxy,
subscribeProxies,
upgradeProxyAppliance,
EXPIRES_SOON_DELAY,
Expand Down Expand Up @@ -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}
Expand Down