diff options
Diffstat (limited to 'src/store/modules/Operations')
-rw-r--r-- | src/store/modules/Operations/BootSettingsStore.js | 136 | ||||
-rw-r--r-- | src/store/modules/Operations/ControlStore.js | 132 | ||||
-rw-r--r-- | src/store/modules/Operations/FactoryResetStore.js | 32 | ||||
-rw-r--r-- | src/store/modules/Operations/FirmwareStore.js | 191 | ||||
-rw-r--r-- | src/store/modules/Operations/PowerControlStore.js | 60 | ||||
-rw-r--r-- | src/store/modules/Operations/PowerPolicyStore.js | 72 | ||||
-rw-r--r-- | src/store/modules/Operations/VirtualMediaStore.js | 105 |
7 files changed, 728 insertions, 0 deletions
diff --git a/src/store/modules/Operations/BootSettingsStore.js b/src/store/modules/Operations/BootSettingsStore.js new file mode 100644 index 00000000..7a36dd84 --- /dev/null +++ b/src/store/modules/Operations/BootSettingsStore.js @@ -0,0 +1,136 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; + +const BootSettingsStore = { + namespaced: true, + state: { + bootSourceOptions: [], + bootSource: null, + overrideEnabled: null, + tpmEnabled: null, + }, + getters: { + bootSourceOptions: (state) => state.bootSourceOptions, + bootSource: (state) => state.bootSource, + overrideEnabled: (state) => state.overrideEnabled, + tpmEnabled: (state) => state.tpmEnabled, + }, + mutations: { + setBootSourceOptions: (state, bootSourceOptions) => + (state.bootSourceOptions = bootSourceOptions), + setBootSource: (state, bootSource) => (state.bootSource = bootSource), + setOverrideEnabled: (state, overrideEnabled) => { + if (overrideEnabled === 'Once') { + state.overrideEnabled = true; + } else { + // 'Continuous' or 'Disabled' + state.overrideEnabled = false; + } + }, + setTpmPolicy: (state, tpmEnabled) => (state.tpmEnabled = tpmEnabled), + }, + actions: { + async getBootSettings({ commit }) { + return await api + .get('/redfish/v1/Systems/system') + .then(({ data: { Boot } }) => { + commit( + 'setBootSourceOptions', + Boot['BootSourceOverrideTarget@Redfish.AllowableValues'] + ); + commit('setOverrideEnabled', Boot.BootSourceOverrideEnabled); + commit('setBootSource', Boot.BootSourceOverrideTarget); + }) + .catch((error) => console.log(error)); + }, + saveBootSettings({ commit, dispatch }, { bootSource, overrideEnabled }) { + const data = { Boot: {} }; + data.Boot.BootSourceOverrideTarget = bootSource; + + if (overrideEnabled) { + data.Boot.BootSourceOverrideEnabled = 'Once'; + } else if (bootSource === 'None') { + data.Boot.BootSourceOverrideEnabled = 'Disabled'; + } else { + data.Boot.BootSourceOverrideEnabled = 'Continuous'; + } + + return api + .patch('/redfish/v1/Systems/system', data) + .then((response) => { + // If request success, commit the values + commit('setBootSource', data.Boot.BootSourceOverrideTarget); + commit('setOverrideEnabled', data.Boot.BootSourceOverrideEnabled); + return response; + }) + .catch((error) => { + console.log(error); + // If request error, GET saved options + dispatch('getBootSettings'); + return error; + }); + }, + async getTpmPolicy({ commit }) { + // TODO: switch to Redfish when available + return await api + .get('/xyz/openbmc_project/control/host0/TPMEnable') + .then(({ data: { data: { TPMEnable } } }) => + commit('setTpmPolicy', TPMEnable) + ) + .catch((error) => console.log(error)); + }, + saveTpmPolicy({ commit, dispatch }, tpmEnabled) { + // TODO: switch to Redfish when available + const data = { data: tpmEnabled }; + return api + .put( + '/xyz/openbmc_project/control/host0/TPMEnable/attr/TPMEnable', + data + ) + .then((response) => { + // If request success, commit the values + commit('setTpmPolicy', tpmEnabled); + return response; + }) + .catch((error) => { + console.log(error); + // If request error, GET saved policy + dispatch('getTpmPolicy'); + return error; + }); + }, + async saveSettings( + { dispatch }, + { bootSource, overrideEnabled, tpmEnabled } + ) { + const promises = []; + + if (bootSource !== null || overrideEnabled !== null) { + promises.push( + dispatch('saveBootSettings', { bootSource, overrideEnabled }) + ); + } + if (tpmEnabled !== null) { + promises.push(dispatch('saveTpmPolicy', tpmEnabled)); + } + + return await api.all(promises).then( + api.spread((...responses) => { + let message = i18n.t( + 'pageServerPowerOperations.toast.successSaveSettings' + ); + responses.forEach((response) => { + if (response instanceof Error) { + throw new Error( + i18n.t('pageServerPowerOperations.toast.errorSaveSettings') + ); + } + }); + return message; + }) + ); + }, + }, +}; + +export default BootSettingsStore; diff --git a/src/store/modules/Operations/ControlStore.js b/src/store/modules/Operations/ControlStore.js new file mode 100644 index 00000000..9b8bf73d --- /dev/null +++ b/src/store/modules/Operations/ControlStore.js @@ -0,0 +1,132 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; + +/** + * Watch for serverStatus changes in GlobalStore module + * to set isOperationInProgress state + * Stop watching status changes and resolve Promise when + * serverStatus value matches passed argument or after 5 minutes + * @param {string} serverStatus + * @returns {Promise} + */ +const checkForServerStatus = function (serverStatus) { + return new Promise((resolve) => { + const timer = setTimeout(() => { + resolve(); + unwatch(); + }, 300000 /*5mins*/); + const unwatch = this.watch( + (state) => state.global.serverStatus, + (value) => { + if (value === serverStatus) { + resolve(); + unwatch(); + clearTimeout(timer); + } + } + ); + }); +}; + +const ControlStore = { + namespaced: true, + state: { + isOperationInProgress: false, + lastPowerOperationTime: null, + lastBmcRebootTime: null, + }, + getters: { + isOperationInProgress: (state) => state.isOperationInProgress, + lastPowerOperationTime: (state) => state.lastPowerOperationTime, + lastBmcRebootTime: (state) => state.lastBmcRebootTime, + }, + mutations: { + setOperationInProgress: (state, inProgress) => + (state.isOperationInProgress = inProgress), + setLastPowerOperationTime: (state, lastPowerOperationTime) => + (state.lastPowerOperationTime = lastPowerOperationTime), + setLastBmcRebootTime: (state, lastBmcRebootTime) => + (state.lastBmcRebootTime = lastBmcRebootTime), + }, + actions: { + async getLastPowerOperationTime({ commit }) { + return await api + .get('/redfish/v1/Systems/system') + .then((response) => { + const lastReset = response.data.LastResetTime; + if (lastReset) { + const lastPowerOperationTime = new Date(lastReset); + commit('setLastPowerOperationTime', lastPowerOperationTime); + } + }) + .catch((error) => console.log(error)); + }, + getLastBmcRebootTime({ commit }) { + return api + .get('/redfish/v1/Managers/bmc') + .then((response) => { + const lastBmcReset = response.data.LastResetTime; + const lastBmcRebootTime = new Date(lastBmcReset); + commit('setLastBmcRebootTime', lastBmcRebootTime); + }) + .catch((error) => console.log(error)); + }, + async rebootBmc({ dispatch }) { + const data = { ResetType: 'GracefulRestart' }; + return await api + .post('/redfish/v1/Managers/bmc/Actions/Manager.Reset', data) + .then(() => dispatch('getLastBmcRebootTime')) + .then(() => i18n.t('pageRebootBmc.toast.successRebootStart')) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageRebootBmc.toast.errorRebootStart')); + }); + }, + async serverPowerOn({ dispatch, commit }) { + const data = { ResetType: 'On' }; + dispatch('serverPowerChange', data); + await checkForServerStatus.bind(this, 'on')(); + commit('setOperationInProgress', false); + dispatch('getLastPowerOperationTime'); + }, + async serverSoftReboot({ dispatch, commit }) { + const data = { ResetType: 'GracefulRestart' }; + dispatch('serverPowerChange', data); + await checkForServerStatus.bind(this, 'on')(); + commit('setOperationInProgress', false); + dispatch('getLastPowerOperationTime'); + }, + async serverHardReboot({ dispatch, commit }) { + const data = { ResetType: 'ForceRestart' }; + dispatch('serverPowerChange', data); + await checkForServerStatus.bind(this, 'on')(); + commit('setOperationInProgress', false); + dispatch('getLastPowerOperationTime'); + }, + async serverSoftPowerOff({ dispatch, commit }) { + const data = { ResetType: 'GracefulShutdown' }; + dispatch('serverPowerChange', data); + await checkForServerStatus.bind(this, 'off')(); + commit('setOperationInProgress', false); + dispatch('getLastPowerOperationTime'); + }, + async serverHardPowerOff({ dispatch, commit }) { + const data = { ResetType: 'ForceOff' }; + dispatch('serverPowerChange', data); + await checkForServerStatus.bind(this, 'off')(); + commit('setOperationInProgress', false); + dispatch('getLastPowerOperationTime'); + }, + serverPowerChange({ commit }, data) { + commit('setOperationInProgress', true); + api + .post('/redfish/v1/Systems/system/Actions/ComputerSystem.Reset', data) + .catch((error) => { + console.log(error); + commit('setOperationInProgress', false); + }); + }, + }, +}; + +export default ControlStore; diff --git a/src/store/modules/Operations/FactoryResetStore.js b/src/store/modules/Operations/FactoryResetStore.js new file mode 100644 index 00000000..8118cf7f --- /dev/null +++ b/src/store/modules/Operations/FactoryResetStore.js @@ -0,0 +1,32 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; + +const FactoryResetStore = { + namespaced: true, + actions: { + async resetToDefaults() { + return await api + .post('/redfish/v1/Managers/bmc/Actions/Manager.ResetToDefaults', { + ResetToDefaultsType: 'ResetAll', + }) + .then(() => i18n.t('pageFactoryReset.toast.resetToDefaultsSuccess')) + .catch((error) => { + console.log('Factory Reset: ', error); + throw new Error( + i18n.t('pageFactoryReset.toast.resetToDefaultsError') + ); + }); + }, + async resetBios() { + return await api + .post('/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios') + .then(() => i18n.t('pageFactoryReset.toast.resetBiosSuccess')) + .catch((error) => { + console.log('Factory Reset: ', error); + throw new Error(i18n.t('pageFactoryReset.toast.resetBiosError')); + }); + }, + }, +}; + +export default FactoryResetStore; diff --git a/src/store/modules/Operations/FirmwareStore.js b/src/store/modules/Operations/FirmwareStore.js new file mode 100644 index 00000000..c6639ff7 --- /dev/null +++ b/src/store/modules/Operations/FirmwareStore.js @@ -0,0 +1,191 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; + +const FirmwareStore = { + namespaced: true, + state: { + bmcFirmware: [], + hostFirmware: [], + bmcActiveFirmwareId: null, + hostActiveFirmwareId: null, + applyTime: null, + tftpAvailable: false, + }, + getters: { + isTftpUploadAvailable: (state) => state.tftpAvailable, + isSingleFileUploadEnabled: (state) => state.hostFirmware.length === 0, + activeBmcFirmware: (state) => { + return state.bmcFirmware.find( + (firmware) => firmware.id === state.bmcActiveFirmwareId + ); + }, + activeHostFirmware: (state) => { + return state.hostFirmware.find( + (firmware) => firmware.id === state.hostActiveFirmwareId + ); + }, + backupBmcFirmware: (state) => { + return state.bmcFirmware.find( + (firmware) => firmware.id !== state.bmcActiveFirmwareId + ); + }, + backupHostFirmware: (state) => { + return state.hostFirmware.find( + (firmware) => firmware.id !== state.hostActiveFirmwareId + ); + }, + }, + mutations: { + setActiveBmcFirmwareId: (state, id) => (state.bmcActiveFirmwareId = id), + setActiveHostFirmwareId: (state, id) => (state.hostActiveFirmwareId = id), + setBmcFirmware: (state, firmware) => (state.bmcFirmware = firmware), + setHostFirmware: (state, firmware) => (state.hostFirmware = firmware), + setApplyTime: (state, applyTime) => (state.applyTime = applyTime), + setTftpUploadAvailable: (state, tftpAvailable) => + (state.tftpAvailable = tftpAvailable), + }, + actions: { + async getFirmwareInformation({ dispatch }) { + dispatch('getActiveHostFirmware'); + dispatch('getActiveBmcFirmware'); + return await dispatch('getFirmwareInventory'); + }, + getActiveBmcFirmware({ commit }) { + return api + .get('/redfish/v1/Managers/bmc') + .then(({ data: { Links } }) => { + const id = Links?.ActiveSoftwareImage['@odata.id'].split('/').pop(); + commit('setActiveBmcFirmwareId', id); + }) + .catch((error) => console.log(error)); + }, + getActiveHostFirmware({ commit }) { + return api + .get('/redfish/v1/Systems/system/Bios') + .then(({ data: { Links } }) => { + const id = Links?.ActiveSoftwareImage['@odata.id'].split('/').pop(); + commit('setActiveHostFirmwareId', id); + }) + .catch((error) => console.log(error)); + }, + async getFirmwareInventory({ commit }) { + const inventoryList = await api + .get('/redfish/v1/UpdateService/FirmwareInventory') + .then(({ data: { Members = [] } = {} }) => + Members.map((item) => api.get(item['@odata.id'])) + ) + .catch((error) => console.log(error)); + await api + .all(inventoryList) + .then((response) => { + const bmcFirmware = []; + const hostFirmware = []; + response.forEach(({ data }) => { + const firmwareType = data?.RelatedItem?.[0]?.['@odata.id'] + .split('/') + .pop(); + const item = { + version: data?.Version, + id: data?.Id, + location: data?.['@odata.id'], + status: data?.Status?.Health, + }; + if (firmwareType === 'bmc') { + bmcFirmware.push(item); + } else if (firmwareType === 'Bios') { + hostFirmware.push(item); + } + }); + commit('setBmcFirmware', bmcFirmware); + commit('setHostFirmware', hostFirmware); + }) + .catch((error) => { + console.log(error); + }); + }, + getUpdateServiceSettings({ commit }) { + api + .get('/redfish/v1/UpdateService') + .then(({ data }) => { + const applyTime = + data.HttpPushUriOptions.HttpPushUriApplyTime.ApplyTime; + const allowableActions = + data?.Actions?.['#UpdateService.SimpleUpdate']?.[ + 'TransferProtocol@Redfish.AllowableValues' + ]; + + commit('setApplyTime', applyTime); + if (allowableActions?.includes('TFTP')) { + commit('setTftpUploadAvailable', true); + } + }) + .catch((error) => console.log(error)); + }, + setApplyTimeImmediate({ commit }) { + const data = { + HttpPushUriOptions: { + HttpPushUriApplyTime: { + ApplyTime: 'Immediate', + }, + }, + }; + return api + .patch('/redfish/v1/UpdateService', data) + .then(() => commit('setApplyTime', 'Immediate')) + .catch((error) => console.log(error)); + }, + async uploadFirmware({ state, dispatch }, image) { + if (state.applyTime !== 'Immediate') { + // ApplyTime must be set to Immediate before making + // request to update firmware + await dispatch('setApplyTimeImmediate'); + } + return await api + .post('/redfish/v1/UpdateService', image, { + headers: { 'Content-Type': 'application/octet-stream' }, + }) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageFirmware.toast.errorUpdateFirmware')); + }); + }, + async uploadFirmwareTFTP({ state, dispatch }, fileAddress) { + const data = { + TransferProtocol: 'TFTP', + ImageURI: fileAddress, + }; + if (state.applyTime !== 'Immediate') { + // ApplyTime must be set to Immediate before making + // request to update firmware + await dispatch('setApplyTimeImmediate'); + } + return await api + .post( + '/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate', + data + ) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageFirmware.toast.errorUpdateFirmware')); + }); + }, + async switchBmcFirmwareAndReboot({ getters }) { + const backupLocation = getters.backupBmcFirmware.location; + const data = { + Links: { + ActiveSoftwareImage: { + '@odata.id': backupLocation, + }, + }, + }; + return await api + .patch('/redfish/v1/Managers/bmc', data) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageFirmware.toast.errorSwitchImages')); + }); + }, + }, +}; + +export default FirmwareStore; diff --git a/src/store/modules/Operations/PowerControlStore.js b/src/store/modules/Operations/PowerControlStore.js new file mode 100644 index 00000000..9dbddf05 --- /dev/null +++ b/src/store/modules/Operations/PowerControlStore.js @@ -0,0 +1,60 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; + +const PowerControlStore = { + namespaced: true, + state: { + powerCapValue: null, + powerConsumptionValue: null, + }, + getters: { + powerCapValue: (state) => state.powerCapValue, + powerConsumptionValue: (state) => state.powerConsumptionValue, + }, + mutations: { + setPowerCapValue: (state, powerCapValue) => + (state.powerCapValue = powerCapValue), + setPowerConsumptionValue: (state, powerConsumptionValue) => + (state.powerConsumptionValue = powerConsumptionValue), + }, + actions: { + setPowerCapUpdatedValue({ commit }, value) { + commit('setPowerCapValue', value); + }, + async getPowerControl({ commit }) { + return await api + .get('/redfish/v1/Chassis/chassis/Power') + .then((response) => { + const powerControl = response.data.PowerControl; + const powerCap = powerControl[0].PowerLimit.LimitInWatts; + // If system is powered off, power consumption does not exist in the PowerControl + const powerConsumption = powerControl[0].PowerConsumedWatts || null; + + commit('setPowerCapValue', powerCap); + commit('setPowerConsumptionValue', powerConsumption); + }) + .catch((error) => { + console.log('Power control', error); + }); + }, + async setPowerControl(_, powerCapValue) { + const data = { + PowerControl: [{ PowerLimit: { LimitInWatts: powerCapValue } }], + }; + + return await api + .patch('/redfish/v1/Chassis/chassis/Power', data) + .then(() => + i18n.t('pageServerPowerOperations.toast.successSaveSettings') + ) + .catch((error) => { + console.log(error); + throw new Error( + i18n.t('pageServerPowerOperations.toast.errorSaveSettings') + ); + }); + }, + }, +}; + +export default PowerControlStore; diff --git a/src/store/modules/Operations/PowerPolicyStore.js b/src/store/modules/Operations/PowerPolicyStore.js new file mode 100644 index 00000000..4e76cdfe --- /dev/null +++ b/src/store/modules/Operations/PowerPolicyStore.js @@ -0,0 +1,72 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; + +const PowerControlStore = { + namespaced: true, + state: { + powerRestoreCurrentPolicy: null, + powerRestorePolicies: [], + }, + getters: { + powerRestoreCurrentPolicy: (state) => state.powerRestoreCurrentPolicy, + powerRestorePolicies: (state) => state.powerRestorePolicies, + }, + mutations: { + setPowerRestoreCurrentPolicy: (state, powerRestoreCurrentPolicy) => + (state.powerRestoreCurrentPolicy = powerRestoreCurrentPolicy), + setPowerRestorePolicies: (state, powerRestorePolicies) => + (state.powerRestorePolicies = powerRestorePolicies), + }, + actions: { + async getPowerRestorePolicies({ commit }) { + return await api + .get('/redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json') + .then( + ({ + data: { + definitions: { PowerRestorePolicyTypes = {} }, + }, + }) => { + let powerPoliciesData = PowerRestorePolicyTypes.enum.map( + (powerState) => { + let desc = `${i18n.t( + `pagePowerRestorePolicy.policies.${powerState}` + )} - ${PowerRestorePolicyTypes.enumDescriptions[powerState]}`; + return { + state: powerState, + desc, + }; + } + ); + commit('setPowerRestorePolicies', powerPoliciesData); + } + ); + }, + async getPowerRestoreCurrentPolicy({ commit }) { + api + .get('/redfish/v1/Systems/system') + .then(({ data: { PowerRestorePolicy } }) => { + commit('setPowerRestoreCurrentPolicy', PowerRestorePolicy); + }) + .catch((error) => console.log(error)); + }, + async setPowerRestorePolicy({ commit }, powerPolicy) { + const data = { PowerRestorePolicy: powerPolicy }; + + return await api + .patch('/redfish/v1/Systems/system', data) + .then(() => + commit('setPowerRestoreCurrentPolicy', data.PowerRestorePolicy) + ) + .then(() => i18n.t('pagePowerRestorePolicy.toast.successSaveSettings')) + .catch((error) => { + console.log(error); + throw new Error( + i18n.t('pagePowerRestorePolicy.toast.errorSaveSettings') + ); + }); + }, + }, +}; + +export default PowerControlStore; diff --git a/src/store/modules/Operations/VirtualMediaStore.js b/src/store/modules/Operations/VirtualMediaStore.js new file mode 100644 index 00000000..7c183b0e --- /dev/null +++ b/src/store/modules/Operations/VirtualMediaStore.js @@ -0,0 +1,105 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; + +const VirtualMediaStore = { + namespaced: true, + state: { + proxyDevices: [], + legacyDevices: [], + connections: [], + }, + getters: { + proxyDevices: (state) => state.proxyDevices, + legacyDevices: (state) => state.legacyDevices, + }, + mutations: { + setProxyDevicesData: (state, deviceData) => + (state.proxyDevices = deviceData), + setLegacyDevicesData: (state, deviceData) => + (state.legacyDevices = deviceData), + }, + actions: { + async getData({ commit }) { + const virtualMediaListEnabled = + process.env.VUE_APP_VIRTUAL_MEDIA_LIST_ENABLED === 'true' + ? true + : false; + if (!virtualMediaListEnabled) { + const device = { + id: i18n.t('pageVirtualMedia.defaultDeviceName'), + websocket: '/vm/0/0', + file: null, + transferProtocolType: 'OEM', + isActive: false, + }; + commit('setProxyDevicesData', [device]); + return; + } + + return await api + .get('/redfish/v1/Managers/bmc/VirtualMedia') + .then((response) => + response.data.Members.map((virtualMedia) => virtualMedia['@odata.id']) + ) + .then((devices) => api.all(devices.map((device) => api.get(device)))) + .then((devices) => { + const deviceData = devices.map((device) => { + const isActive = device.data?.Inserted === true ? true : false; + return { + id: device.data?.Id, + transferProtocolType: device.data?.TransferProtocolType, + websocket: device.data?.Oem?.OpenBMC?.WebSocketEndpoint, + isActive: isActive, + }; + }); + const proxyDevices = deviceData + .filter((d) => d.transferProtocolType === 'OEM') + .map((device) => { + return { + ...device, + file: null, + }; + }); + const legacyDevices = deviceData + .filter((d) => !d.transferProtocolType) + .map((device) => { + return { + ...device, + serverUri: '', + username: '', + password: '', + isRW: false, + }; + }); + commit('setProxyDevicesData', proxyDevices); + commit('setLegacyDevicesData', legacyDevices); + }) + .catch((error) => { + console.log('Virtual Media:', error); + }); + }, + async mountImage(_, { id, data }) { + return await api + .post( + `/redfish/v1/Managers/bmc/VirtualMedia/${id}/Actions/VirtualMedia.InsertMedia`, + data + ) + .catch((error) => { + console.log('Mount image:', error); + throw new Error(); + }); + }, + async unmountImage(_, id) { + return await api + .post( + `/redfish/v1/Managers/bmc/VirtualMedia/${id}/Actions/VirtualMedia.EjectMedia` + ) + .catch((error) => { + console.log('Unmount image:', error); + throw new Error(); + }); + }, + }, +}; + +export default VirtualMediaStore; |