feat(xo-web/settings/servers): display connection issues (#4310)

Fixes #4300
This commit is contained in:
HamadaBrest
2019-07-04 10:19:44 +02:00
committed by Julien Fontanet
parent 863e4f0c19
commit c7aaeca530
15 changed files with 60 additions and 73 deletions

View File

@@ -3,6 +3,7 @@
### Enhancements
- [Stats] Ability to display last day stats [#4160](https://github.com/vatesfr/xen-orchestra/issues/4160) (PR [#4168](https://github.com/vatesfr/xen-orchestra/pull/4168))
- [Settings/servers] Display servers connection issues [#4300](https://github.com/vatesfr/xen-orchestra/issues/4300) (PR [#4310](https://github.com/vatesfr/xen-orchestra/pull/4310))
### Bug fixes
@@ -12,5 +13,6 @@
### Released packages
- xo-server-sdn-controller v0.1.1
- xen-api v0.26.0
- xo-server v5.45.0
- xo-web v5.45.0

View File

@@ -99,6 +99,9 @@ export class Xapi extends EventEmitter {
this._sessionId = undefined
this._status = DISCONNECTED
this._watchEventsError = undefined
this._lastEventFetchedTimestamp = undefined
this._debounce = opts.debounce ?? 200
this._objects = new Collection()
this._objectsByRef = { __proto__: null }
@@ -479,6 +482,14 @@ export class Xapi extends EventEmitter {
return this._objectsFetched
}
get lastEventFetchedTimestamp() {
return this._lastEventFetchedTimestamp
}
get watchEventsError() {
return this._watchEventsError
}
// ensure we have received all events up to this call
//
// optionally returns the up to date object for the given ref
@@ -954,6 +965,8 @@ export class Xapi extends EventEmitter {
],
EVENT_TIMEOUT * 1e3 * 1.1
)
this._lastEventFetchedTimestamp = Date.now()
this._watchEventsError = undefined
} catch (error) {
const code = error?.code
if (code === 'EVENTS_LOST' || code === 'SESSION_INVALID') {
@@ -961,6 +974,7 @@ export class Xapi extends EventEmitter {
continue mainLoop
}
this._watchEventsError = error
console.warn('_watchEvents', error)
await pDelay(this._eventPollDelay)
continue

View File

@@ -29,6 +29,9 @@ guessVhdSizeOnImport = false
# be turned for investigation by the administrator.
verboseApiLogsOnErrors = false
# if no events could be fetched during this delay, the server will be marked as disconnected
xapiMarkDisconnectedDelay = '5 minutes'
# https:#github.com/websockets/ws#websocket-compression
[apiWebSocketOptions]
perMessageDeflate = { threshold = 524288 } # 512kiB

View File

@@ -108,16 +108,16 @@ set.params = {
// -------------------------------------------------------------------
export async function connect({ id }) {
export async function enable({ id }) {
this.updateXenServer(id, { enabled: true })::ignoreErrors()
await this.connectXenServer(id)
}
connect.description = 'connect a Xen server'
enable.description = 'enable a Xen server'
connect.permission = 'admin'
enable.permission = 'admin'
connect.params = {
enable.params = {
id: {
type: 'string',
},
@@ -125,16 +125,16 @@ connect.params = {
// -------------------------------------------------------------------
export async function disconnect({ id }) {
export async function disable({ id }) {
this.updateXenServer(id, { enabled: false })::ignoreErrors()
await this.disconnectXenServer(id)
}
disconnect.description = 'disconnect a Xen server'
disable.description = 'disable a Xen server'
disconnect.permission = 'admin'
disable.permission = 'admin'
disconnect.params = {
disable.params = {
id: {
type: 'string',
},

View File

@@ -5,6 +5,7 @@ import { noSuchObject } from 'xo-common/api-errors'
import { pDelay, ignoreErrors } from 'promise-toolbox'
import * as XenStore from '../_XenStore'
import parseDuration from '../_parseDuration'
import Xapi from '../xapi'
import xapiObjectToXo from '../xapi-object-to-xo'
import XapiStats from '../xapi-stats'
@@ -40,7 +41,10 @@ const log = createLogger('xo:xo-mixins:xen-servers')
// - _xapis[server.id] id defined
// - _serverIdsByPool[xapi.pool.$id] is server.id
export default class {
constructor(xo, { guessVhdSizeOnImport, xapiOptions }) {
constructor(
xo,
{ guessVhdSizeOnImport, xapiMarkDisconnectedDelay, xapiOptions }
) {
this._objectConflicts = { __proto__: null } // TODO: clean when a server is disconnected.
const serversDb = (this._servers = new Servers({
connection: xo._redis,
@@ -55,6 +59,7 @@ export default class {
}
this._xapis = { __proto__: null }
this._xo = xo
this._xapiMarkDisconnectedDelay = parseDuration(xapiMarkDisconnectedDelay)
xo.on('clean', () => serversDb.rebuildIndexes())
xo.on('start', async () => {
@@ -472,6 +477,14 @@ export default class {
const servers = await this._servers.get()
const xapis = this._xapis
forEach(servers, server => {
const lastEventFetchedTimestamp =
xapis[server.id]?.lastEventFetchedTimestamp
if (
lastEventFetchedTimestamp !== undefined &&
Date.now() > lastEventFetchedTimestamp + this._xapiMarkDisconnectedDelay
) {
server.error = xapis[server.id].watchEventsError
}
server.status = this._getXenServerStatus(server.id)
if (server.status === 'connected') {
server.poolId = xapis[server.id].pool.uuid

View File

@@ -3058,9 +3058,6 @@ export default {
// Original text: "Enable it if your certificate is rejected, but it's not recommended because your connection will not be secured."
serverUnauthorizedCertificatesInfo: undefined,
// Original text: 'Disconnect server'
serverDisconnect: undefined,
// Original text: 'username'
serverPlaceHolderUser: undefined,
@@ -3091,12 +3088,6 @@ export default {
// Original text: 'Connecting…'
serverConnecting: undefined,
// Original text: 'Connected'
serverConnected: undefined,
// Original text: 'Disconnected'
serverDisconnected: undefined,
// Original text: 'Authentication error'
serverAuthFailed: undefined,

View File

@@ -3135,9 +3135,6 @@ export default {
serverUnauthorizedCertificatesInfo:
"Activez ceci si votre certificat est rejeté, mais ce n'est pas recommandé car votre connexion ne sera pas sécurisée.",
// Original text: "Disconnect server"
serverDisconnect: 'Déconnecter le serveur',
// Original text: "username"
serverPlaceHolderUser: "nom d'utilisateur",
@@ -3169,12 +3166,6 @@ export default {
// Original text: "Connecting…"
serverConnecting: 'Connexion…',
// Original text: "Connected"
serverConnected: 'Connecté',
// Original text: "Disconnected"
serverDisconnected: 'Déconnecté',
// Original text: "Authentication error"
serverAuthFailed: "Erreur d'authentification",

View File

@@ -2612,9 +2612,6 @@ export default {
// Original text: 'Read Only'
serverReadOnly: undefined,
// Original text: 'Disconnect server'
serverDisconnect: undefined,
// Original text: 'username'
serverPlaceHolderUser: undefined,

View File

@@ -2909,9 +2909,6 @@ export default {
// Original text: "Read Only"
serverReadOnly: 'Csak Olvasható',
// Original text: "Disconnect server"
serverDisconnect: 'Szerver Lecsatlakozás',
// Original text: "username"
serverPlaceHolderUser: 'felhasználónév',
@@ -2939,12 +2936,6 @@ export default {
// Original text: "Connecting…"
serverConnecting: 'Csatlakozás…',
// Original text: "Connected"
serverConnected: 'Kapcsolódva',
// Original text: "Disconnected"
serverDisconnected: 'Lekapcsolódva',
// Original text: "Authentication error"
serverAuthFailed: 'Bejelentkezési hiba',

View File

@@ -2648,9 +2648,6 @@ export default {
// Original text: "Read Only"
serverReadOnly: 'Tylko do odczytu',
// Original text: "Disconnect server"
serverDisconnect: 'Rozłącz serwer',
// Original text: "username"
serverPlaceHolderUser: 'Użytkownik',

View File

@@ -2636,9 +2636,6 @@ export default {
// Original text: "Read Only"
serverReadOnly: 'Modo Leitura',
// Original text: 'Disconnect server'
serverDisconnect: undefined,
// Original text: 'username'
serverPlaceHolderUser: undefined,

View File

@@ -3916,9 +3916,6 @@ export default {
serverUnauthorizedCertificatesInfo:
'Sertifikanız reddedildiğinde bunu yapın ancak bağlantınız güvenli olmayacağı için tavsiye edilmez.',
// Original text: "Disconnect server"
serverDisconnect: 'Sunucu bağlantısını kes',
// Original text: "username"
serverPlaceHolderUser: 'kullanıcı adı',
@@ -3949,12 +3946,6 @@ export default {
// Original text: "Connecting…"
serverConnecting: 'Bağlanıyor...',
// Original text: "Connected"
serverConnected: 'Bağlandı',
// Original text: "Disconnected"
serverDisconnected: 'Bağlantı kesildi',
// Original text: "Authentication error"
serverAuthFailed: 'Kimlik doğrulama hatası',

View File

@@ -1662,7 +1662,6 @@ const messages = {
serverAllowUnauthorizedCertificates: 'Allow Unauthorized Certificates',
serverUnauthorizedCertificatesInfo:
"Enable it if your certificate is rejected, but it's not recommended because your connection will not be secured.",
serverDisconnect: 'Disconnect server',
serverPlaceHolderUser: 'username',
serverPlaceHolderPassword: 'password',
serverPlaceHolderAddress: 'address[:port]',
@@ -1672,13 +1671,15 @@ const messages = {
serverAddFailed: 'Adding server failed',
serverStatus: 'Status',
serverConnectionFailed: 'Connection failed. Click for more information.',
serverConnected: 'Connected',
serverDisconnected: 'Disconnected',
serverAuthFailed: 'Authentication error',
serverUnknownError: 'Unknown error',
serverSelfSignedCertError: 'Invalid self-signed certificate',
serverSelfSignedCertQuestion:
'Do you want to accept self-signed certificate for this server even though it would decrease security?',
serverEnable: 'Enable',
serverEnabled: 'Enabled',
serverDisabled: 'Disabled',
serverDisable: 'Disable server',
// ----- Copy VM -----
copyVm: 'Copy VM',

View File

@@ -536,13 +536,13 @@ export const editServer = (server, props) =>
subscribeServers.forceRefresh
)
export const connectServer = server =>
_call('server.connect', { id: resolveId(server) })::pFinally(
export const enableServer = server =>
_call('server.enable', { id: resolveId(server) })::pFinally(
subscribeServers.forceRefresh
)
export const disconnectServer = server =>
_call('server.disconnect', { id: resolveId(server) })::tap(
export const disableServer = server =>
_call('server.disable', { id: resolveId(server) })::tap(
subscribeServers.forceRefresh
)

View File

@@ -16,9 +16,9 @@ import { injectIntl } from 'react-intl'
import { noop } from 'lodash'
import {
addServer,
disableServer,
editServer,
connectServer,
disconnectServer,
enableServer,
removeServer,
subscribeServers,
} from 'xo'
@@ -38,7 +38,7 @@ const showServerError = server => {
}).then(
() =>
editServer(server, { allowUnauthorized: true }).then(() =>
connectServer(server)
enableServer(server)
),
noop
)
@@ -100,17 +100,16 @@ const COLUMNS = [
itemRenderer: server => (
<div>
<StateButton
disabledLabel={_('serverDisconnected')}
disabledHandler={connectServer}
disabledTooltip={_('serverConnect')}
enabledLabel={_('serverConnected')}
enabledHandler={disconnectServer}
enabledTooltip={_('serverDisconnect')}
disabledLabel={_('serverDisabled')}
disabledHandler={enableServer}
disabledTooltip={_('serverEnable')}
enabledLabel={_('serverEnabled')}
enabledHandler={disableServer}
enabledTooltip={_('serverDisable')}
handlerParam={server}
pending={server.status === 'connecting'}
state={server.status === 'connected'}
state={server.enabled}
/>{' '}
{server.error && (
{server.error != null && (
<Tooltip content={_('serverConnectionFailed')}>
<a
className='text-danger btn btn-link btn-sm'