* feat(xo-server-sdn-controller): Dynamically monitor xapis dis/connection to XO (fixes #4649) * fill changelog.unreleased.md * adapt ro PR comments * rename methods * refactor code * Update packages/xo-server-sdn-controller/src/index.js Co-Authored-By: badrAZ <azizbibadr@gmail.com> * refactor * Update CHANGELOG.unreleased.md Co-Authored-By: Julien Fontanet <julien.fontanet@isonoe.net> * Update CHANGELOG.unreleased.md Co-Authored-By: Julien Fontanet <julien.fontanet@isonoe.net> * use native array map * Better name for setControllerNeeded * add try/catch block * use correct check on objects * fix previous commit * remove useless emit Co-authored-by: badrAZ <azizbibadr@gmail.com> Co-authored-by: Julien Fontanet <julien.fontanet@isonoe.net>
This commit is contained in:
@@ -8,12 +8,14 @@
|
||||
> Users must be able to say: “Nice enhancement, I'm eager to test it”
|
||||
|
||||
- [New VM] Ability to set VM max vCPUS [#4703](https://github.com/vatesfr/xen-orchestra/issues/4703) (PR [#4729](https://github.com/vatesfr/xen-orchestra/pull/4729))
|
||||
- [SDN Controller] Automatically handle new, connected and disconnected servers (PR [#4677](https://github.com/vatesfr/xen-orchestra/pull/4677))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
> Users must be able to say: “I had this issue, happy to know it's fixed”
|
||||
|
||||
- [Usage Report] Fix wrong report date [#4779](https://github.com/vatesfr/xen-orchestra/issues/4779) (PR [#4799](https://github.com/vatesfr/xen-orchestra/pull/4799))
|
||||
- [SDN Controller] Fix plugin stuck loading [#4649](https://github.com/vatesfr/xen-orchestra/issues/4649) (PR [#4677](https://github.com/vatesfr/xen-orchestra/pull/4677))
|
||||
|
||||
### Released packages
|
||||
|
||||
@@ -23,5 +25,6 @@
|
||||
> Rule of thumb: add packages on top.
|
||||
|
||||
- xo-server-usage-report v0.7.4
|
||||
- xo-server-sdn-controller v0.4.0
|
||||
- xo-server v5.57.0
|
||||
- xo-web v5.57.0
|
||||
|
||||
@@ -275,7 +275,7 @@ function getHostTunnelForNetwork(host, networkRef) {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
function setControllerNeeded(xapi) {
|
||||
function isControllerNeeded(xapi) {
|
||||
const controller = find(xapi.objects.all, { $type: 'SDN_controller' })
|
||||
return !(
|
||||
controller?.protocol === PROTOCOL &&
|
||||
@@ -418,126 +418,21 @@ class SDNController extends EventEmitter {
|
||||
},
|
||||
})
|
||||
|
||||
// FIXME: we should monitor when xapis are added/removed
|
||||
this._xapis = this._xo.getAllXapis()
|
||||
await Promise.all(
|
||||
map(this._xapis, async xapi => {
|
||||
await xapi.objectsFetched
|
||||
forOwn(this._xo.getAllXapis(), xapi => {
|
||||
if (xapi.status === 'connected') {
|
||||
this._handleConnectedXapi(xapi)
|
||||
}
|
||||
})
|
||||
|
||||
if (setControllerNeeded(xapi)) {
|
||||
return
|
||||
}
|
||||
|
||||
this._cleaners.push(await this._manageXapi(xapi))
|
||||
const hosts = filter(xapi.objects.all, { $type: 'host' })
|
||||
for (const host of hosts) {
|
||||
this._createOvsdbClient(host)
|
||||
}
|
||||
|
||||
// Add already existing private networks
|
||||
const networks = filter(xapi.objects.all, { $type: 'network' })
|
||||
const noVniNetworks = []
|
||||
await Promise.all(
|
||||
map(networks, async network => {
|
||||
// 2019-09-03
|
||||
// Compatibility code, to be removed in 1 year.
|
||||
await updateNetworkOtherConfig(network)
|
||||
network = await network.$xapi.barrier(network.$ref)
|
||||
let otherConfig = network.other_config
|
||||
|
||||
// 2019-10-01
|
||||
// To be removed in a year
|
||||
if (otherConfig['xo:sdn-controller:private-pool-wide'] === 'true') {
|
||||
await updateOldPrivateNetwork(network)
|
||||
}
|
||||
network = await network.$xapi.barrier(network.$ref)
|
||||
otherConfig = network.other_config
|
||||
|
||||
const uuid = otherConfig['xo:sdn-controller:private-network-uuid']
|
||||
if (uuid === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
let privateNetwork = this._privateNetworks[uuid]
|
||||
if (privateNetwork === undefined) {
|
||||
privateNetwork = new PrivateNetwork(this, uuid)
|
||||
this._privateNetworks[uuid] = privateNetwork
|
||||
}
|
||||
|
||||
const vni = otherConfig['xo:sdn-controller:vni']
|
||||
if (vni === undefined) {
|
||||
noVniNetworks.push(network)
|
||||
} else {
|
||||
this._prevVni = Math.max(this._prevVni, +vni)
|
||||
}
|
||||
|
||||
await privateNetwork.addNetwork(network)
|
||||
|
||||
// Previously created network didn't store `pif-device`
|
||||
//
|
||||
// 2019-08-22
|
||||
// This is used to add the `pif-device` to networks created before this version. (v0.1.2)
|
||||
// This will be removed in 1 year.
|
||||
if (otherConfig['xo:sdn-controller:pif-device'] === undefined) {
|
||||
const tunnel = getHostTunnelForNetwork(
|
||||
privateNetwork.center,
|
||||
network.$ref
|
||||
)
|
||||
const pif = xapi.getObjectByRef(tunnel.transport_PIF)
|
||||
await network.update_other_config(
|
||||
'xo:sdn-controller:pif-device',
|
||||
pif.device
|
||||
)
|
||||
}
|
||||
|
||||
// Previously created network didn't store `vlan`
|
||||
//
|
||||
// 2020-01-27
|
||||
// This is used to add the `vlan` to networks created before this version. (v0.4.0)
|
||||
// This will be removed in 1 year.
|
||||
if (otherConfig['xo:sdn-controller:vlan'] === undefined) {
|
||||
const tunnel = getHostTunnelForNetwork(
|
||||
privateNetwork.center,
|
||||
network.$ref
|
||||
)
|
||||
const pif = xapi.getObjectByRef(tunnel.transport_PIF)
|
||||
await network.update_other_config(
|
||||
'xo:sdn-controller:vlan',
|
||||
String(pif.VLAN)
|
||||
)
|
||||
}
|
||||
|
||||
this._networks.set(network.$id, network.$ref)
|
||||
if (privateNetwork.center !== undefined) {
|
||||
this._starCenters.set(
|
||||
privateNetwork.center.$id,
|
||||
privateNetwork.center.$ref
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// Add VNI to other config of networks without VNI
|
||||
//
|
||||
// 2019-08-22
|
||||
// This is used to add the VNI to networks created before this version. (v0.1.3)
|
||||
// This will be removed in 1 year.
|
||||
await Promise.all(
|
||||
map(noVniNetworks, async network => {
|
||||
await network.update_other_config(
|
||||
'xo:sdn-controller:vni',
|
||||
String(++this._prevVni)
|
||||
)
|
||||
|
||||
// Re-elect a center to apply the VNI
|
||||
const privateNetwork = this._privateNetworks[
|
||||
network.other_config['private-network-uuid']
|
||||
]
|
||||
await this._electNewCenter(privateNetwork)
|
||||
})
|
||||
)
|
||||
})
|
||||
)
|
||||
const handleConnectedServer = ({ xapi }) => this._handleConnectedXapi(xapi)
|
||||
const handleDisconnectedServer = ({ xapi }) =>
|
||||
this._handleDisconnectedXapi(xapi)
|
||||
this._xo.on('server:connected', handleConnectedServer)
|
||||
this._xo.on('server:disconnected', handleDisconnectedServer)
|
||||
this._cleaners.push(() => {
|
||||
this._xo.removeListener('server:connected', handleConnectedServer)
|
||||
this._xo.removeListener('server:disconnected', handleDisconnectedServer)
|
||||
})
|
||||
}
|
||||
|
||||
async unload() {
|
||||
@@ -557,6 +452,159 @@ class SDNController extends EventEmitter {
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
async _handleConnectedXapi(xapi) {
|
||||
log.debug('xapi connected', { id: xapi.pool.uuid })
|
||||
try {
|
||||
await xapi.objectsFetched
|
||||
|
||||
if (isControllerNeeded(xapi)) {
|
||||
return
|
||||
}
|
||||
|
||||
this._cleaners.push(await this._manageXapi(xapi))
|
||||
const hosts = filter(xapi.objects.all, { $type: 'host' })
|
||||
for (const host of hosts) {
|
||||
this._createOvsdbClient(host)
|
||||
}
|
||||
|
||||
// Add already existing private networks
|
||||
const networks = filter(xapi.objects.all, { $type: 'network' })
|
||||
const noVniNetworks = []
|
||||
await Promise.all(
|
||||
networks.map(async network => {
|
||||
// 2019-09-03
|
||||
// Compatibility code, to be removed in 1 year.
|
||||
await updateNetworkOtherConfig(network)
|
||||
network = await network.$xapi.barrier(network.$ref)
|
||||
let otherConfig = network.other_config
|
||||
|
||||
// 2019-10-01
|
||||
// To be removed in a year
|
||||
if (otherConfig['xo:sdn-controller:private-pool-wide'] === 'true') {
|
||||
await updateOldPrivateNetwork(network)
|
||||
}
|
||||
network = await network.$xapi.barrier(network.$ref)
|
||||
otherConfig = network.other_config
|
||||
|
||||
const uuid = otherConfig['xo:sdn-controller:private-network-uuid']
|
||||
if (uuid === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
let privateNetwork = this._privateNetworks[uuid]
|
||||
if (privateNetwork === undefined) {
|
||||
privateNetwork = new PrivateNetwork(this, uuid)
|
||||
this._privateNetworks[uuid] = privateNetwork
|
||||
}
|
||||
|
||||
const vni = otherConfig['xo:sdn-controller:vni']
|
||||
if (vni === undefined) {
|
||||
noVniNetworks.push(network)
|
||||
} else {
|
||||
this._prevVni = Math.max(this._prevVni, +vni)
|
||||
}
|
||||
|
||||
await privateNetwork.addNetwork(network)
|
||||
|
||||
// Previously created network didn't store `pif-device`
|
||||
//
|
||||
// 2019-08-22
|
||||
// This is used to add the pif-device to networks created before this version. (v0.1.2)
|
||||
// This will be removed in 1 year.
|
||||
if (otherConfig['xo:sdn-controller:pif-device'] === undefined) {
|
||||
const tunnel = getHostTunnelForNetwork(
|
||||
privateNetwork.center,
|
||||
network.$ref
|
||||
)
|
||||
const pif = xapi.getObjectByRef(tunnel.transport_PIF)
|
||||
await network.update_other_config(
|
||||
'xo:sdn-controller:pif-device',
|
||||
pif.device
|
||||
)
|
||||
}
|
||||
|
||||
// Previously created network didn't store `vlan`
|
||||
//
|
||||
// 2020-01-27
|
||||
// This is used to add the `vlan` to networks created before this version. (v0.4.0)
|
||||
// This will be removed in 1 year.
|
||||
if (otherConfig['xo:sdn-controller:vlan'] === undefined) {
|
||||
const tunnel = getHostTunnelForNetwork(
|
||||
privateNetwork.center,
|
||||
network.$ref
|
||||
)
|
||||
const pif = xapi.getObjectByRef(tunnel.transport_PIF)
|
||||
await network.update_other_config(
|
||||
'xo:sdn-controller:vlan',
|
||||
String(pif.VLAN)
|
||||
)
|
||||
}
|
||||
|
||||
this._networks.set(network.$id, network.$ref)
|
||||
if (privateNetwork.center !== undefined) {
|
||||
this._starCenters.set(
|
||||
privateNetwork.center.$id,
|
||||
privateNetwork.center.$ref
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// Add VNI to other config of networks without VNI
|
||||
//
|
||||
// 2019-08-22
|
||||
// This is used to add the VNI to networks created before this version. (v0.1.3)
|
||||
// This will be removed in 1 year.
|
||||
await Promise.all(
|
||||
noVniNetworks.map(async network => {
|
||||
await network.update_other_config(
|
||||
'xo:sdn-controller:vni',
|
||||
String(++this._prevVni)
|
||||
)
|
||||
|
||||
// Re-elect a center to apply the VNI
|
||||
const privateNetwork = this._privateNetworks[
|
||||
network.other_config['private-network-uuid']
|
||||
]
|
||||
await this._electNewCenter(privateNetwork)
|
||||
})
|
||||
)
|
||||
} catch (error) {
|
||||
log.error('Error while handling xapi connection', {
|
||||
id: xapi.pool.uuid,
|
||||
error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_handleDisconnectedXapi(xapi) {
|
||||
log.debug('xapi disconnected', { id: xapi.pool.uuid })
|
||||
try {
|
||||
forOwn(this._privateNetworks, privateNetwork => {
|
||||
privateNetwork.networks = omitBy(
|
||||
privateNetwork.networks,
|
||||
network => network.$pool.uuid === xapi.pool.uuid
|
||||
)
|
||||
|
||||
if (privateNetwork.center?.$pool.uuid === xapi.pool.uuid) {
|
||||
this._electNewCenter(privateNetwork)
|
||||
}
|
||||
})
|
||||
|
||||
this._privateNetworks = filter(
|
||||
this._privateNetworks,
|
||||
privateNetwork => Object.keys(privateNetwork.networks).length !== 0
|
||||
)
|
||||
} catch (error) {
|
||||
log.error('Error while handling xapi disconnection', {
|
||||
id: xapi.pool.uuid,
|
||||
error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
async _createPrivateNetwork({
|
||||
poolIds,
|
||||
pifIds,
|
||||
@@ -716,6 +764,11 @@ class SDNController extends EventEmitter {
|
||||
network => network.$ref === networkRef
|
||||
)
|
||||
})
|
||||
|
||||
this._privateNetworks = filter(
|
||||
this._privateNetworks,
|
||||
privateNetwork => Object.keys(privateNetwork.networks).length !== 0
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('Error in _objectsRemoved', {
|
||||
@@ -831,7 +884,7 @@ class SDNController extends EventEmitter {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async _setPoolControllerIfNeeded(pool) {
|
||||
if (!setControllerNeeded(pool.$xapi)) {
|
||||
if (!isControllerNeeded(pool.$xapi)) {
|
||||
// Nothing to do
|
||||
return
|
||||
}
|
||||
|
||||
@@ -445,7 +445,9 @@ export default class {
|
||||
xapi.xo.uninstall()
|
||||
delete this._xapis[server.id]
|
||||
delete this._serverIdsByPool[poolId]
|
||||
this._xo.emit('server:disconnected', { server, xapi })
|
||||
})
|
||||
this._xo.emit('server:connected', { server, xapi })
|
||||
} catch (error) {
|
||||
delete this._xapis[server.id]
|
||||
xapi.disconnect()::ignoreErrors()
|
||||
|
||||
Reference in New Issue
Block a user