diff --git a/src/api/sr.js b/src/api/sr.js index 2c933d4d5..7548e1d0c 100644 --- a/src/api/sr.js +++ b/src/api/sr.js @@ -817,3 +817,17 @@ reattachIso.params = { reattachIso.resolve = { host: ['host', 'host', 'administrate'] } + +// ------------------------------------------------------------------- + +export function getUnhealthyVdiChainsLength ({ sr }) { + return this.getXapi(sr).getUnhealthyVdiChainsLength(sr) +} + +getUnhealthyVdiChainsLength.params = { + id: { type: 'string' } +} + +getUnhealthyVdiChainsLength.resolve = { + sr: ['id', 'SR', 'operate'] +} diff --git a/src/xapi/index.js b/src/xapi/index.js index c2a8d07b3..5bfa79934 100644 --- a/src/xapi/index.js +++ b/src/xapi/index.js @@ -739,14 +739,16 @@ export default class Xapi extends XapiBase { return promise } - _assertHealthyVdiChain (vdi, childrenMap) { + _assertHealthyVdiChain (vdi, cache) { if (vdi == null) { return } if (!vdi.managed) { + const { SR } = vdi + let childrenMap = cache[SR] if (childrenMap === undefined) { - childrenMap = groupBy(vdi.$SR.$VDIs, _ => _.sm_config['vhd-parent']) + childrenMap = cache[SR] = groupBy(vdi.$SR.$VDIs, _ => _.sm_config['vhd-parent']) } // an unmanaged VDI should not have exactly one child: they @@ -762,13 +764,14 @@ export default class Xapi extends XapiBase { this._assertHealthyVdiChain( this.getObjectByUuid(vdi.sm_config['vhd-parent'], null), - childrenMap + cache ) } _assertHealthyVdiChains (vm) { + const cache = createRawObject() forEach(vm.$VBDs, ({ $VDI }) => { - this._assertHealthyVdiChain($VDI) + this._assertHealthyVdiChain($VDI, cache) }) } diff --git a/src/xapi/mixins/storage.js b/src/xapi/mixins/storage.js index f6b863d30..a9c4155dd 100644 --- a/src/xapi/mixins/storage.js +++ b/src/xapi/mixins/storage.js @@ -1,4 +1,10 @@ import { + forEach, + groupBy +} from 'lodash' + +import { + createRawObject, mapToArray } from '../../utils' @@ -49,5 +55,38 @@ export default { async unplugPbd (id) { await this._unplugPbd(this.getObject(id)) + }, + + _getUnhealthyVdiChainLength (uuid, childrenMap, cache) { + let length = cache[uuid] + if (length === undefined) { + const children = childrenMap[uuid] + length = children !== undefined && children.length === 1 + ? 1 + : 0 + const parent = this.getObjectByUuid(uuid).sm_config['vhd-parent'] + if (parent !== undefined) { + length += this._getUnhealthyVdiChainLength(parent, childrenMap, cache) + } + cache[uuid] = length + } + return length + }, + + getUnhealthyVdiChainsLength (sr) { + const vdis = this.getObject(sr).$VDIs + const unhealthyVdis = createRawObject() + const children = groupBy(vdis, 'sm_config.vhd-parent') + const cache = createRawObject() + forEach(vdis, vdi => { + if (vdi.managed && !vdi.is_a_snapshot) { + const { uuid } = vdi + const length = this._getUnhealthyVdiChainLength(uuid, children, cache) + if (length !== 0) { + unhealthyVdis[uuid] = length + } + } + }) + return unhealthyVdis } }