feat(xen-api/{get,put}Resource): use default migration network if available (#5883)
This commit is contained in:
parent
85abc42100
commit
ea10df8a92
@ -10,6 +10,7 @@
|
|||||||
- [New network] Ability for pool's admin to create a new network within the pool (PR [#5873](https://github.com/vatesfr/xen-orchestra/pull/5873))
|
- [New network] Ability for pool's admin to create a new network within the pool (PR [#5873](https://github.com/vatesfr/xen-orchestra/pull/5873))
|
||||||
- [Netbox] Synchronize primary IPv4 and IPv6 addresses [#5633](https://github.com/vatesfr/xen-orchestra/issues/5633) (PR [#5879](https://github.com/vatesfr/xen-orchestra/pull/5879))
|
- [Netbox] Synchronize primary IPv4 and IPv6 addresses [#5633](https://github.com/vatesfr/xen-orchestra/issues/5633) (PR [#5879](https://github.com/vatesfr/xen-orchestra/pull/5879))
|
||||||
- [Host] Add warning in case of unmaintained host version [#5840](https://github.com/vatesfr/xen-orchestra/issues/5840) (PR [#5847](https://github.com/vatesfr/xen-orchestra/pull/5847))
|
- [Host] Add warning in case of unmaintained host version [#5840](https://github.com/vatesfr/xen-orchestra/issues/5840) (PR [#5847](https://github.com/vatesfr/xen-orchestra/pull/5847))
|
||||||
|
- [Backup] Use default migration network if set when importing/exporting VMs/VDIs (PR [#5883](https://github.com/vatesfr/xen-orchestra/pull/5883))
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
|
||||||
@ -37,6 +38,9 @@
|
|||||||
>
|
>
|
||||||
> In case of conflict, the highest (lowest in previous list) `$version` wins.
|
> In case of conflict, the highest (lowest in previous list) `$version` wins.
|
||||||
|
|
||||||
|
- xen-api minor
|
||||||
|
- @xen-orchestra/xapi minor
|
||||||
|
- @xen-orchestra/backups minor
|
||||||
- @xen-orchestra/fs minor
|
- @xen-orchestra/fs minor
|
||||||
- @xen-orchestra/log minor
|
- @xen-orchestra/log minor
|
||||||
- @xen-orchestra/mixins patch
|
- @xen-orchestra/mixins patch
|
||||||
|
@ -6,7 +6,17 @@ import httpRequest from 'http-request-plus'
|
|||||||
import { Collection } from 'xo-collection'
|
import { Collection } from 'xo-collection'
|
||||||
import { EventEmitter } from 'events'
|
import { EventEmitter } from 'events'
|
||||||
import { map, noop, omit } from 'lodash'
|
import { map, noop, omit } from 'lodash'
|
||||||
import { cancelable, defer, fromCallback, fromEvents, ignoreErrors, pDelay, pRetry, pTimeout } from 'promise-toolbox'
|
import {
|
||||||
|
cancelable,
|
||||||
|
defer,
|
||||||
|
fromCallback,
|
||||||
|
fromEvents,
|
||||||
|
ignoreErrors,
|
||||||
|
pDelay,
|
||||||
|
pRetry,
|
||||||
|
pTimeout,
|
||||||
|
retry,
|
||||||
|
} from 'promise-toolbox'
|
||||||
import { limitConcurrency } from 'limit-concurrency-decorator'
|
import { limitConcurrency } from 'limit-concurrency-decorator'
|
||||||
|
|
||||||
import autoTransport from './transports/auto'
|
import autoTransport from './transports/auto'
|
||||||
@ -359,22 +369,35 @@ export class Xapi extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await httpRequest(
|
let url = new URL('http://localhost')
|
||||||
$cancelToken,
|
url.protocol = this._url.protocol
|
||||||
this._url,
|
url.hostname = await this._getHostAddress(await this.getRecord('host', host ?? this._pool.master))
|
||||||
host !== undefined && {
|
url.pathname = pathname
|
||||||
hostname: await this._getHostAddress(this.getObject(host)),
|
url.search = new URLSearchParams(query)
|
||||||
},
|
|
||||||
|
const response = await retry(
|
||||||
|
async () =>
|
||||||
|
httpRequest($cancelToken, url.href, {
|
||||||
|
rejectUnauthorized: !this._allowUnauthorized,
|
||||||
|
|
||||||
|
// this is an inactivity timeout (unclear in Node doc)
|
||||||
|
timeout: this._httpInactivityTimeout,
|
||||||
|
|
||||||
|
maxRedirects: 0,
|
||||||
|
|
||||||
|
// Support XS <= 6.5 with Node => 12
|
||||||
|
minVersion: 'TLSv1',
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
pathname,
|
when: { code: 302 },
|
||||||
query,
|
onRetry: async error => {
|
||||||
rejectUnauthorized: !this._allowUnauthorized,
|
const response = error.response
|
||||||
|
if (response === undefined) {
|
||||||
// this is an inactivity timeout (unclear in Node doc)
|
throw error
|
||||||
timeout: this._httpInactivityTimeout,
|
}
|
||||||
|
response.cancel()
|
||||||
// Support XS <= 6.5 with Node => 12
|
url = await this._replaceHostAddressInUrl(new URL(response.headers.location, url))
|
||||||
minVersion: 'TLSv1',
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -421,32 +444,28 @@ export class Xapi extends EventEmitter {
|
|||||||
headers['content-length'] = '1125899906842624'
|
headers['content-length'] = '1125899906842624'
|
||||||
}
|
}
|
||||||
|
|
||||||
const doRequest = httpRequest.put.bind(
|
const url = new URL('http://localhost')
|
||||||
undefined,
|
url.protocol = this._url.protocol
|
||||||
$cancelToken,
|
url.hostname = await this._getHostAddress(await this.getRecord('host', host ?? this._pool.master))
|
||||||
this._url,
|
url.pathname = pathname
|
||||||
host !== undefined && {
|
url.search = new URLSearchParams(query)
|
||||||
hostname: await this._getHostAddress(this.getObject(host)),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
body,
|
|
||||||
headers,
|
|
||||||
pathname,
|
|
||||||
query,
|
|
||||||
rejectUnauthorized: !this._allowUnauthorized,
|
|
||||||
|
|
||||||
// this is an inactivity timeout (unclear in Node doc)
|
const doRequest = httpRequest.put.bind(undefined, $cancelToken, {
|
||||||
timeout: this._httpInactivityTimeout,
|
body,
|
||||||
|
headers,
|
||||||
|
rejectUnauthorized: !this._allowUnauthorized,
|
||||||
|
|
||||||
// Support XS <= 6.5 with Node => 12
|
// this is an inactivity timeout (unclear in Node doc)
|
||||||
minVersion: 'TLSv1',
|
timeout: this._httpInactivityTimeout,
|
||||||
}
|
|
||||||
)
|
// Support XS <= 6.5 with Node => 12
|
||||||
|
minVersion: 'TLSv1',
|
||||||
|
})
|
||||||
|
|
||||||
// if body is a stream, sends a dummy request to probe for a redirection
|
// if body is a stream, sends a dummy request to probe for a redirection
|
||||||
// before consuming body
|
// before consuming body
|
||||||
const response = await (isStream
|
const response = await (isStream
|
||||||
? doRequest({
|
? doRequest(url.href, {
|
||||||
body: '',
|
body: '',
|
||||||
|
|
||||||
// omit task_id because this request will fail on purpose
|
// omit task_id because this request will fail on purpose
|
||||||
@ -456,9 +475,9 @@ export class Xapi extends EventEmitter {
|
|||||||
}).then(
|
}).then(
|
||||||
response => {
|
response => {
|
||||||
response.cancel()
|
response.cancel()
|
||||||
return doRequest()
|
return doRequest(url.href)
|
||||||
},
|
},
|
||||||
error => {
|
async error => {
|
||||||
let response
|
let response
|
||||||
if (error != null && (response = error.response) != null) {
|
if (error != null && (response = error.response) != null) {
|
||||||
response.cancel()
|
response.cancel()
|
||||||
@ -469,7 +488,9 @@ export class Xapi extends EventEmitter {
|
|||||||
} = response
|
} = response
|
||||||
if (statusCode === 302 && location !== undefined) {
|
if (statusCode === 302 && location !== undefined) {
|
||||||
// ensure the original query is sent
|
// ensure the original query is sent
|
||||||
return doRequest(location, { query })
|
const newUrl = new URL(location, url)
|
||||||
|
newUrl.searchParams.set('task_id', query.task_id)
|
||||||
|
return doRequest((await this._replaceHostAddressInUrl(newUrl)).href)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,7 +813,20 @@ export class Xapi extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _getHostAddress({ address }) {
|
async _getHostAddress({ address, PIFs, $pool }) {
|
||||||
|
const poolMigrationNetwork = $pool.other_config['xo:migrationNetwork']
|
||||||
|
if (poolMigrationNetwork !== undefined) {
|
||||||
|
const _PIFs = new Set(PIFs)
|
||||||
|
try {
|
||||||
|
const migrationNetworkPifRef = (await this.getRecordByUuid('network', poolMigrationNetwork)).PIFs.find(pifRef =>
|
||||||
|
_PIFs.has(pifRef)
|
||||||
|
)
|
||||||
|
address = await this.getField('PIF', migrationNetworkPifRef, 'IP')
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('unable to get the host address linked to the pool migration network', poolMigrationNetwork, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this._reverseHostIpAddresses) {
|
if (this._reverseHostIpAddresses) {
|
||||||
try {
|
try {
|
||||||
;[address] = await fromCallback(dns.reverse, address)
|
;[address] = await fromCallback(dns.reverse, address)
|
||||||
@ -862,6 +896,19 @@ export class Xapi extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _replaceHostAddressInUrl(url) {
|
||||||
|
try {
|
||||||
|
// TODO: look for hostname in all addresses of this host (including all its PIFs)
|
||||||
|
const host = (await this.getAllRecords('host')).find(host => host.address === url.hostname)
|
||||||
|
if (host !== undefined) {
|
||||||
|
url.hostname = await this._getHostAddress(host)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('_replaceHostAddressInUrl', url, error)
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
_processEvents(events) {
|
_processEvents(events) {
|
||||||
const flush = this._objects.bufferEvents()
|
const flush = this._objects.bufferEvents()
|
||||||
events.forEach(event => {
|
events.forEach(event => {
|
||||||
|
Loading…
Reference in New Issue
Block a user