From c05ff648da07d8e2221d67eac83b6c6581d371a0 Mon Sep 17 00:00:00 2001 From: Yoshie Muranaka Date: Wed, 26 Feb 2020 14:23:15 -0800 Subject: Add host boot settings to power operations page Added BootSettingsStore and component to handle changing boot source, boot override option and TPM required option. Signed-off-by: Yoshie Muranaka Change-Id: I885dd6008aceb34b319953a2e9b6416d848baf16 --- src/assets/styles/_form-components.scss | 10 ++ src/locales/en-US.json | 12 ++ src/store/index.js | 2 + src/store/modules/Control/BootSettingsStore.js | 136 +++++++++++++++++++ .../Control/ServerPowerOperations/BootSettings.vue | 148 +++++++++++++++++++++ .../ServerPowerOperations.vue | 20 ++- 6 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 src/store/modules/Control/BootSettingsStore.js create mode 100644 src/views/Control/ServerPowerOperations/BootSettings.vue diff --git a/src/assets/styles/_form-components.scss b/src/assets/styles/_form-components.scss index 89abfb3f..35274e70 100644 --- a/src/assets/styles/_form-components.scss +++ b/src/assets/styles/_form-components.scss @@ -25,3 +25,13 @@ border-bottom: 2px solid $danger !important; } } + +.custom-control { + .custom-control-input[disabled=disabled] { + & + .custom-control-label { + // Disabled label for checkbox, radio, + // switch bootstrap form components + color: $gray-700!important; + } + } +} diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 8a77b931..0bf40513 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -183,9 +183,11 @@ "pageServerPowerOperations": { "currentStatus": "Current status", "hostname": "Hostname", + "hostOsBootSettings": "Host OS boot settings", "hostStatus": "Host status", "immediateReboot": "Immediate – Server reboots without OS shutting down; may cause data corruption", "immediateShutdown": "Immediate - Server shuts down without OS shutting down; may cause data corruption", + "oneTimeBootWarning": "Pending one time boot. Next boot will be performed with the specified one time boot settings. Subsequent boots will be performed with the default settings.", "operationInProgress": "There are no options to display while a power operation is in progress. When complete, power operations will be displayed here.", "operations": "Operations", "orderlyReboot": "Orderly – OS shuts down, then server reboots", @@ -195,11 +197,21 @@ "rebootServer": "Reboot server", "shutDown": "Shut down", "shutdownServer": "Shutdown server", + "bootSettings": { + "bootSettingsOverride": "Boot settings override", + "enableOneTimeBoot": "Enable one time boot", + "tpmRequiredPolicy": "TPM required policy", + "tpmRequiredPolicyHelper": "Enable to ensure the system only boots when the TPM is functional." + }, "modal": { "confirmRebootMessage": "Are you sure you want to reboot?", "confirmRebootTitle": "Server reboot will cause outage", "confirmShutdownMessage": "Are you sure you want to shut down?", "confirmShutdownTitle": "Server shutdown will cause outage" + }, + "toast": { + "errorSaveSettings": "Error saving settings.", + "successSaveSettings": "Successfully saved settings." } } } \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js index 6bad517c..27216990 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -6,6 +6,7 @@ import AuthenticationStore from './modules/Authentication/AuthenticanStore'; import LocalUserManagementStore from './modules/AccessControl/LocalUserMangementStore'; import OverviewStore from './modules/Overview/OverviewStore'; import FirmwareStore from './modules/Configuration/FirmwareStore'; +import BootSettingsStore from './modules/Control/BootSettingsStore'; import ControlStore from './modules/Control/ControlStore'; import PowerControlStore from './modules/Control/PowerControlStore'; import NetworkSettingStore from './modules/Configuration/NetworkSettingsStore'; @@ -25,6 +26,7 @@ export default new Vuex.Store({ localUsers: LocalUserManagementStore, overview: OverviewStore, firmware: FirmwareStore, + hostBootSettings: BootSettingsStore, controls: ControlStore, powerControl: PowerControlStore, networkSettings: NetworkSettingStore, diff --git a/src/store/modules/Control/BootSettingsStore.js b/src/store/modules/Control/BootSettingsStore.js new file mode 100644 index 00000000..8da586aa --- /dev/null +++ b/src/store/modules/Control/BootSettingsStore.js @@ -0,0 +1,136 @@ +import api from '../../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: { + getBootSettings({ commit }) { + 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; + }); + }, + getTpmPolicy({ commit }) { + // TODO: switch to Redfish when available + 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/views/Control/ServerPowerOperations/BootSettings.vue b/src/views/Control/ServerPowerOperations/BootSettings.vue new file mode 100644 index 00000000..c912749f --- /dev/null +++ b/src/views/Control/ServerPowerOperations/BootSettings.vue @@ -0,0 +1,148 @@ + + + + + diff --git a/src/views/Control/ServerPowerOperations/ServerPowerOperations.vue b/src/views/Control/ServerPowerOperations/ServerPowerOperations.vue index c9b02b3e..e63d0732 100644 --- a/src/views/Control/ServerPowerOperations/ServerPowerOperations.vue +++ b/src/views/Control/ServerPowerOperations/ServerPowerOperations.vue @@ -2,7 +2,7 @@ - + @@ -26,10 +26,20 @@ - + + + + + + + + {{ $t('pageServerPowerOperations.oneTimeBootWarning') }} + @@ -101,10 +111,11 @@ import PageTitle from '../../../components/Global/PageTitle'; import PageSection from '../../../components/Global/PageSection'; import BVToastMixin from '../../../components/Mixins/BVToastMixin'; +import BootSettings from './BootSettings'; export default { name: 'ServerPowerOperations', - components: { PageTitle, PageSection }, + components: { PageTitle, PageSection, BootSettings }, mixins: [BVToastMixin], data() { return { @@ -123,6 +134,9 @@ export default { }, isOperationInProgress() { return this.$store.getters['controls/isOperationInProgress']; + }, + oneTimeBootEnabled() { + return this.$store.getters['hostBootSettings/overrideEnabled']; } }, created() { -- cgit v1.2.3