From 9a98353618d13ee4ae2a724cf3e58aca848d09e0 Mon Sep 17 00:00:00 2001 From: Alexandr Ilenko Date: Thu, 15 Sep 2022 18:16:54 +0300 Subject: [SILABMC-248] Fix: add redfish transition state polling for VirtualMedia (store) --- src/store/modules/Operations/VirtualMediaStore.js | 142 +++++++++++++++++++++- 1 file changed, 138 insertions(+), 4 deletions(-) (limited to 'src/store') diff --git a/src/store/modules/Operations/VirtualMediaStore.js b/src/store/modules/Operations/VirtualMediaStore.js index 5cd8f98c..b9eefa2b 100644 --- a/src/store/modules/Operations/VirtualMediaStore.js +++ b/src/store/modules/Operations/VirtualMediaStore.js @@ -19,6 +19,13 @@ const VirtualMediaStore = { proxyDevices: [], legacyDevices: [], connections: [], + // VirtualMedia`s log shows some 90 secs timeout (nbd-client`s output) + // kernel log shows some ~90 secs timeout in ndb device driver + // Let`s use 2*60 secs. Experiments showed it is enough by the moment. + legacyDevicesTransitionStateInitialTimeout: 2 * 60, + legacyDevicesTransitionStateZeroTimeout: 0, + legacyDevicesTransitionStatePollInterval: 1, + legacyDevicesTransitionStateTimerId: null, }, getters: { proxyDevices: (state) => state.proxyDevices, @@ -29,9 +36,26 @@ const VirtualMediaStore = { (state.proxyDevices = deviceData), setLegacyDevicesData: (state, deviceData) => (state.legacyDevices = deviceData), + setLegacyDevicesTransitionStateTimerId: (state, newTimerId) => { + if (state.legacyDevicesTransitionStateTimerId != null) { + clearTimeout(state.legacyDevicesTransitionStateTimerId); + } + state.legacyDevicesTransitionStateTimerId = newTimerId; + }, + patchLegacyDevice: (state, devicePatch) => { + state.legacyDevices = state.legacyDevices.map((device) => { + if (device.id === devicePatch.id) { + device = { + ...device, + ...devicePatch, + }; + } + return device; + }); + }, }, actions: { - async getData({ commit }) { + async getData({ commit, state }) { const virtualMediaListEnabled = process.env.VUE_APP_VIRTUAL_MEDIA_LIST_ENABLED === 'true' ? true @@ -43,6 +67,7 @@ const VirtualMediaStore = { file: null, transferProtocolType: transferProtocolType.OEM, isActive: false, + isConnected: undefined, }; commit('setProxyDevicesData', [device]); return; @@ -56,12 +81,30 @@ const VirtualMediaStore = { .then((devices) => api.all(devices.map((device) => api.get(device)))) .then((devices) => { const deviceData = devices.map((device) => { + const id = device.data?.Id; const isActive = device.data?.Inserted === true ? true : false; + const isConnected = device.data?.ConnectedVia !== undefined; + let serverUri = device.data?.Image; + let isRW = device.data?.WriteProtected === false ? true : false; + if (serverUri === undefined) { + const device = state.legacyDevices.find( + (device) => device.id === id + ); + if (device !== undefined) { + serverUri = device.serverUri; + isRW = device.isRW; + } else { + serverUri = ''; + } + } return { - id: device.data?.Id, + id: id, transferProtocolType: device.data?.TransferProtocolType, websocket: device.data?.Oem?.OpenBMC?.WebSocketEndpoint, isActive: isActive, + isConnected: isConnected, + serverUri: serverUri, + isRW: isRW, }; }); const proxyDevices = deviceData @@ -75,12 +118,20 @@ const VirtualMediaStore = { const legacyDevices = deviceData .filter((d) => d.transferProtocolType !== transferProtocolType.OEM) .map((device) => { + let newTimeout = state.legacyDevicesTransitionStateZeroTimeout; + if (device.isConnected && !device.isActive) { + this.dispatch( + 'virtualMedia/pollLegacyDevicesTransitionState', + device.id + ); + // re-commit the state + newTimeout = state.legacyDevicesTransitionStateInitialTimeout; + } return { ...device, - serverUri: '', username: '', password: '', - isRW: false, + legacyDeviceTransitionStateTimeout: newTimeout, }; }); proxyDevices.sort((a, b) => a.id.localeCompare(b.id)); @@ -92,12 +143,92 @@ const VirtualMediaStore = { console.log('Virtual Media:', error); }); }, + async getLegacyDeviceData({ commit, state }, id) { + const device = state.legacyDevices.find((device) => device.id === id); + let newTimeout = device.legacyDeviceTransitionStateTimeout - 1; + if ( + device.legacyDeviceTransitionStateTimeout % + state.legacyDevicesTransitionStatePollInterval != + 0 + ) { + const devicePatch = { + id: id, + legacyDeviceTransitionStateTimeout: newTimeout, + }; + commit('patchLegacyDevice', devicePatch); + return; + } + return await api + .get(`/redfish/v1/Managers/bmc/VirtualMedia/${id}`) + .then((response) => { + if (response.data?.Id !== id) { + console.log( + `VirtualMedia: Error: expected_id=${id}, actual_id=${response.data?.Id}` + ); + } + const isActive = response.data?.Inserted === true ? true : false; + const isConnected = response.data?.ConnectedVia !== undefined; + if (!(isConnected && !isActive)) { + newTimeout = device.legacyDevicesTransitionStateZeroTimeout - 1; + } + const devicePatch = { + id: id, + isActive: isActive, + isConnected: isConnected, + legacyDeviceTransitionStateTimeout: newTimeout, + }; + commit('patchLegacyDevice', devicePatch); + }) + .catch((error) => { + console.log('Virtual Media:', error); + }); + }, + async pollLegacyDevicesTransitionState({ commit, state }, id = undefined) { + let needRescheduling = false; + if (id !== undefined) { + const devicePatch = { + id: id, + isConnected: true, + isActive: false, + legacyDeviceTransitionStateTimeout: + state.legacyDevicesTransitionStateInitialTimeout, + }; + commit('patchLegacyDevice', devicePatch); + needRescheduling = true; + } else { + const devicesCount = state.legacyDevices + .filter((device) => { + return ( + device.isConnected && + !device.isActive && + device.legacyDeviceTransitionStateTimeout > + state.legacyDevicesTransitionStateZeroTimeout + ); + }) + .map((device) => { + this.dispatch('virtualMedia/getLegacyDeviceData', device.id); + }) + .reduce((previous) => previous + 1, 0); + needRescheduling = devicesCount > 0; + } + let newRescheduleTimerId = null; + if (needRescheduling) { + const pollTimeout = 1 * 1000; + newRescheduleTimerId = setTimeout(() => { + this.dispatch('virtualMedia/pollLegacyDevicesTransitionState'); + }, pollTimeout); + } + commit('setLegacyDevicesTransitionStateTimerId', newRescheduleTimerId); + }, async mountImage(_, { id, data }) { return await api .post( `/redfish/v1/Managers/bmc/VirtualMedia/${id}/Actions/VirtualMedia.InsertMedia`, data ) + .then(() => { + this.dispatch('virtualMedia/pollLegacyDevicesTransitionState', id); + }) .catch((error) => { console.log('Mount image:', error); throw new Error(); @@ -108,6 +239,9 @@ const VirtualMediaStore = { .post( `/redfish/v1/Managers/bmc/VirtualMedia/${id}/Actions/VirtualMedia.EjectMedia` ) + .then(() => { + this.dispatch('virtualMedia/pollLegacyDevicesTransitionState', id); + }) .catch((error) => { console.log('Unmount image:', error); throw new Error(); -- cgit v1.2.3