feat(xo-server): use @xen-orchestra/mixins/Config

This commit is contained in:
Julien Fontanet 2021-04-13 14:41:02 +02:00
parent d1113d40aa
commit a4e7fd3209
15 changed files with 59 additions and 57 deletions

View File

@ -130,6 +130,8 @@ port = 80
[http.mounts]
'/' = '../xo-web/dist'
[plugins]
[remoteOptions]
mountsDir = '/run/xo-server/mounts'

View File

@ -49,7 +49,7 @@ createJob.params = {
}
export function getSuggestedExcludedTags() {
return ['Continuous Replication', 'Disaster Recovery', 'XOSAN', this._config['xo-proxy'].vmTag]
return ['Continuous Replication', 'Disaster Recovery', 'XOSAN', this.config.get('xo-proxy.vmTag')]
}
export function migrateLegacyJob({ id }) {

View File

@ -262,7 +262,7 @@ async function setUpPassport(express, xo, { authentication: authCfg, http: { coo
next()
} else {
req.flash('return-url', url)
res.redirect(authCfg.defaultSignInPage)
res.redirect(xo.config.get('authentication.defaultSignInPage'))
}
})
@ -295,14 +295,15 @@ async function registerPlugin(pluginPath, pluginName) {
let { default: factory = plugin, configurationSchema, configurationPresets, testSchema } = plugin
let instance
const config = this._config
const datadir = this.config.get('datadir')
const pluginsConfig = this.config.get('plugins')
const handleFactory = factory =>
typeof factory === 'function'
? factory({
staticConfig: config.plugins?.[pluginName] ?? {},
staticConfig: pluginsConfig[pluginName] ?? {},
xo: this,
getDataDir: () => {
const dir = `${config.datadir}/${pluginName}`
const dir = `${datadir}/${pluginName}`
return ensureDir(dir).then(() => dir)
},
})

View File

@ -356,7 +356,7 @@ export default class Api {
})
}
if (app._config.verboseLogsOnErrors) {
if (app.config.get('verboseLogsOnErrors')) {
log.warn(message, { error })
} else {
log.warn(`${userName} | ${name}(...) [${ms(Date.now() - startTime)}] =!> ${error}`)

View File

@ -14,10 +14,12 @@ const log = createLogger('xo:authentification')
const noSuchAuthenticationToken = id => noSuchObject(id, 'authenticationToken')
export default class {
constructor(app, { config: { authentication: config } }) {
this._defaultTokenValidity = parseDuration(config.defaultTokenValidity)
this._maxTokenValidity = parseDuration(config.maxTokenValidity)
this._throttlingDelay = parseDuration(config.throttlingDelay)
constructor(app) {
app.config.watch('authentication', config => {
this._defaultTokenValidity = parseDuration(config.defaultTokenValidity)
this._maxTokenValidity = parseDuration(config.maxTokenValidity)
this._throttlingDelay = parseDuration(config.throttlingDelay)
})
this._providers = new Set()
this._app = app

View File

@ -11,7 +11,6 @@ import { formatVmBackups } from '@xen-orchestra/backups/formatVmBackups'
import { forOwn, merge } from 'lodash'
import { ImportVmBackup } from '@xen-orchestra/backups/ImportVmBackup'
import { invalidParameters } from 'xo-common/api-errors'
import { parseDuration } from '@vates/parse-duration'
import { runBackupWorker } from '@xen-orchestra/backups/runBackupWorker'
import { Task } from '@xen-orchestra/backups/Task'
import { type Pattern, createPredicate } from 'value-matcher'
@ -215,16 +214,17 @@ export default class BackupNg {
return this._runningRestores
}
constructor(app: any, { config }) {
constructor(app: any) {
this._app = app
this._logger = undefined
this._runningRestores = new Set()
this._backupOptions = config.backups
app.hooks.on('start', async () => {
this._logger = await app.getLogger('restore')
const executor: Executor = async ({ cancelToken, data, job: job_, logger, runJobId, schedule }) => {
const backupsConfig = app.config.get('backups')
let job: BackupJob = (job_: any)
const vmsPattern = job.vms
@ -256,7 +256,7 @@ export default class BackupNg {
const proxyId = job.proxy
const remoteIds = unboxIdsFromPattern(job.remotes)
try {
if (proxyId === undefined && config.backups.disableWorkers) {
if (proxyId === undefined && backupsConfig.disableWorkers) {
const localTaskIds = { __proto__: null }
return await Task.run(
{
@ -270,7 +270,7 @@ export default class BackupNg {
},
() =>
new Backup({
config: config.backups,
config: backupsConfig,
getAdapter: async remoteId =>
app.getBackupsRemoteAdapter(await app.getRemoteWithCredentials(remoteId)),
@ -363,10 +363,10 @@ export default class BackupNg {
const localTaskIds = { __proto__: null }
return await runBackupWorker(
{
config: config.backups,
remoteOptions: config.remoteOptions,
resourceCacheDelay: parseDuration(config.resourceCacheDelay),
xapiOptions: config.xapiOptions,
config: backupsConfig,
remoteOptions: app.config.get('remoteOptions'),
resourceCacheDelay: app.config.getDuration('resourceCacheDelay'),
xapiOptions: app.config.get('xapiOptions'),
...params,
},
log =>
@ -546,7 +546,7 @@ export default class BackupNg {
@decorateWith(
debounceWithKey,
function () {
return parseDuration(this._backupOptions.listingDebounce)
return this._app.config.getDuration('backups.listingDebounce')
},
function keyFn(remoteId) {
return [this, remoteId]

View File

@ -6,9 +6,8 @@ import { deduped } from '@vates/disposable/deduped'
import { RemoteAdapter } from '@xen-orchestra/backups/RemoteAdapter'
export default class BackupsRemoteAdapter {
constructor(app, { config: { backups } }) {
constructor(app) {
this._app = app
this._config = backups
}
// FIXME: invalidate cache on remote option change
@ -21,7 +20,7 @@ export default class BackupsRemoteAdapter {
const app = this._app
return new RemoteAdapter(await app.getRemoteHandler(remote), {
debounceResource: app.debounceResource.bind(app),
dirMode: this._config.dirMode,
dirMode: app.config.get('backups.dirMode'),
})
}
}

View File

@ -4,7 +4,6 @@ import cloneDeep from 'lodash/cloneDeep'
import Disposable from 'promise-toolbox/Disposable'
import { Backup } from '@xen-orchestra/backups/Backup'
import { createLogger } from '@xen-orchestra/log'
import { parseDuration } from '@vates/parse-duration'
import { parseMetadataBackupId } from '@xen-orchestra/backups/parseMetadataBackupId'
import { RestoreMetadataBackup } from '@xen-orchestra/backups/RestoreMetadataBackup'
import { Task } from '@xen-orchestra/backups/Task'
@ -94,13 +93,12 @@ export default class metadataBackup {
return this._runningMetadataRestores
}
constructor(app: any, { config: { backups } }) {
constructor(app: any) {
this._app = app
this._backupOptions = backups
this._logger = undefined
this._runningMetadataRestores = new Set()
const debounceDelay = parseDuration(backups.listingDebounce)
const debounceDelay = app.config.getDuration('backups.listingDebounce')
this._listXoMetadataBackups = debounceWithKey(this._listXoMetadataBackups, debounceDelay, remoteId => remoteId)
this._listPoolMetadataBackups = debounceWithKey(this._listPoolMetadataBackups, debounceDelay, remoteId => remoteId)
@ -204,7 +202,7 @@ export default class metadataBackup {
},
() =>
new Backup({
config: this._backupOptions,
config: this._app.config.get('backups'),
getAdapter: async remoteId => app.getBackupsRemoteAdapter(await app.getRemoteWithCredentials(remoteId)),
// `@xen-orchestra/backups/Backup` expect that `getConnectedRecord` returns a promise

View File

@ -39,14 +39,15 @@ const assertProxyAddress = (proxy, address) => {
}
export default class Proxy {
constructor(app, { config: conf }) {
constructor(app) {
this._app = app
const xoProxyConf = (this._xoProxyConf = conf['xo-proxy'])
const rules = {
'{date}': (date = new Date()) => date.toISOString(),
}
this._generateDefaultProxyName = compileTemplate(xoProxyConf.proxyName, rules)
this._generateDefaultVmName = compileTemplate(xoProxyConf.vmName, rules)
app.config.watch('xo-proxy', xoProxyConf => {
this._generateDefaultProxyName = compileTemplate(xoProxyConf.proxyName, rules)
this._generateDefaultVmName = compileTemplate(xoProxyConf.vmName, rules)
})
const db = (this._db = new Collection({
connection: app._redis,
indexes: ['address', 'vmUuid'],
@ -97,7 +98,7 @@ export default class Proxy {
await this._app
.unbindLicense({
boundObjectId: vmUuid,
productId: this._xoProxyConf.licenseProductId,
productId: this._app.config.get('xo-proxy.licenseProductId'),
})
.catch(log.warn)
}
@ -166,7 +167,7 @@ export default class Proxy {
xenstoreData['vm-data/xoa-updater-proxy-url'] = JSON.stringify(httpProxy)
}
if (upgrade) {
xenstoreData['vm-data/xoa-updater-channel'] = JSON.stringify(this._xoProxyConf.channel)
xenstoreData['vm-data/xoa-updater-channel'] = JSON.stringify(this._app.config.get('xo-proxy.channel'))
}
const { vmUuid } = await this._getProxy(id)
@ -193,7 +194,7 @@ export default class Proxy {
@defer
async _createProxyVm($defer, srId, licenseId, { httpProxy, networkId, networkConfiguration }) {
const app = this._app
const xoProxyConf = this._xoProxyConf
const xoProxyConf = app.config.get('xo-proxy')
const namespace = xoProxyConf.namespace
const {
@ -261,7 +262,7 @@ export default class Proxy {
async deployProxy(srId, licenseId, { httpProxy, networkConfiguration, networkId, proxyId } = {}) {
const app = this._app
const xoProxyConf = this._xoProxyConf
const xoProxyConf = app.config.get('xo-proxy')
const redeploy = proxyId !== undefined
if (redeploy) {
@ -356,7 +357,7 @@ export default class Proxy {
pathname: '/api/v1',
protocol: 'https:',
rejectUnauthorized: false,
timeout: parseDuration(this._xoProxyConf.callTimeout),
timeout: this._app.config.getDuration('xo-proxy.callTimeout'),
}
if (proxy.vmUuid !== undefined) {

View File

@ -17,9 +17,8 @@ const obfuscateRemote = ({ url, ...remote }) => {
}
export default class {
constructor(app, { config: { remoteOptions } }) {
constructor(app) {
this._handlers = { __proto__: null }
this._remoteOptions = remoteOptions
this._remotes = new Remotes({
connection: app._redis,
prefix: 'xo:remote',
@ -69,7 +68,7 @@ export default class {
const handlers = this._handlers
let handler = handlers[id]
if (handler === undefined) {
handler = getHandler(remote, this._remoteOptions)
handler = getHandler(remote, this._app.config.get('remoteOptions'))
try {
await handler.sync()

View File

@ -115,7 +115,7 @@ export default class {
}
async computeVmSnapshotResourcesUsage(snapshot) {
if (this._app._config.selfService?.ignoreVmSnapshotResources) {
if (this._app.config.get('selfService.ignoreVmSnapshotResources')) {
return {}
}
return this.computeVmResourcesUsage(snapshot)

View File

@ -48,8 +48,8 @@ const valueEncoding = {
}
export default class {
constructor(app, { config }) {
const dir = `${config.datadir}/leveldb`
constructor(app) {
const dir = `${app.config.get('datadir')}/leveldb`
this._db = ensureDir(dir).then(() => levelup(dir))
}

View File

@ -222,7 +222,7 @@ export default class {
return user
}
if (!this._app._config.createUserOnFirstSignin) {
if (!this._app.config.get('createUserOnFirstSignin')) {
throw new Error(`registering ${name} user is forbidden`)
}
@ -251,7 +251,7 @@ export default class {
conflictingUser = users.find(user => user.email === name)
if (conflictingUser !== undefined) {
if (!this._app._config.authentication.mergeProvidersUsers) {
if (!this._app.config.get('authentication.mergeProvidersUsers')) {
throw new Error(`User with username ${name} already exists`)
}
if (user !== undefined) {
@ -269,7 +269,7 @@ export default class {
}
if (user === undefined) {
if (!this._app._config.createUserOnFirstSignin) {
if (!this._app.config.get('createUserOnFirstSignin')) {
throw new Error(`registering ${name} user is forbidden`)
}
user = await this.createUser({

View File

@ -3,7 +3,6 @@ import { createLogger } from '@xen-orchestra/log'
import { fibonacci } from 'iterable-backoff'
import { findKey } from 'lodash'
import { noSuchObject } from 'xo-common/api-errors'
import { parseDuration } from '@vates/parse-duration'
import { pDelay, ignoreErrors } from 'promise-toolbox'
import * as XenStore from '../_XenStore'
@ -36,7 +35,7 @@ const log = createLogger('xo:xo-mixins:xen-servers')
// - _xapis[server.id] id defined
// - _serverIdsByPool[xapi.pool.$id] is server.id
export default class {
constructor(app, { config: { guessVhdSizeOnImport, xapiMarkDisconnectedDelay, xapiOptions }, safeMode }) {
constructor(app, { safeMode }) {
this._objectConflicts = { __proto__: null } // TODO: clean when a server is disconnected.
const serversDb = (this._servers = new Servers({
connection: app._redis,
@ -45,13 +44,12 @@ export default class {
}))
this._serverIdsByPool = { __proto__: null }
this._stats = new XapiStats()
this._xapiOptions = {
guessVhdSizeOnImport,
...xapiOptions,
}
this._xapis = { __proto__: null }
this._app = app
this._xapiMarkDisconnectedDelay = parseDuration(xapiMarkDisconnectedDelay)
app.config.watchDuration('xapiMarkDisconnectedDelay', xapiMarkDisconnectedDelay => {
this._xapiMarkDisconnectedDelay = xapiMarkDisconnectedDelay
})
app.hooks.on('clean', () => serversDb.rebuildIndexes())
app.hooks.on('start', async () => {
@ -272,11 +270,14 @@ export default class {
throw new Error('the server is already connected')
}
const { config } = this._app
const xapi = (this._xapis[server.id] = new Xapi({
allowUnauthorized: server.allowUnauthorized,
readOnly: server.readOnly,
...this._xapiOptions,
...config.get('xapiOptions'),
guessVhdSizeOnImport: config.get('guessVhdSizeOnImport'),
auth: {
user: server.username,

View File

@ -1,3 +1,4 @@
import Config from '@xen-orchestra/mixins/Config'
import Hooks from '@xen-orchestra/mixins/Hooks'
import mixin from '@xen-orchestra/mixin'
import mixinLegacy from '@xen-orchestra/mixin/legacy'
@ -24,15 +25,13 @@ export default class Xo extends EventEmitter {
constructor(opts) {
super()
mixin(this, { Hooks }, [opts])
mixin(this, { Config, Hooks }, [opts])
// a lot of mixins adds listener for start/stop/… events
this.hooks.setMaxListeners(0)
const { config } = opts
this._config = config
this._objects = new XoCollection()
this._objects.createIndex('byRef', new XoUniqueIndex('_xapiRef'))