diff options
-rw-r--r-- | src/components/AppNavigation/AppNavigation.vue | 2 | ||||
-rw-r--r-- | src/locales/en.json | 22 | ||||
-rw-r--r-- | src/router/index.js | 8 | ||||
-rw-r--r-- | src/store/modules/Control/ControlStore.js | 79 | ||||
-rw-r--r-- | src/views/Control/ServerPowerOperations/ServerPowerOperations.vue | 184 | ||||
-rw-r--r-- | src/views/Control/ServerPowerOperations/index.js | 2 |
6 files changed, 296 insertions, 1 deletions
diff --git a/src/components/AppNavigation/AppNavigation.vue b/src/components/AppNavigation/AppNavigation.vue index 62ffe982..07d1cdb9 100644 --- a/src/components/AppNavigation/AppNavigation.vue +++ b/src/components/AppNavigation/AppNavigation.vue @@ -42,7 +42,7 @@ <b-nav-item href="javascript:void(0)"> {{ $t('appNavigation.serverLed') }} </b-nav-item> - <b-nav-item href="javascript:void(0)"> + <b-nav-item to="/control/server-power-operations"> {{ $t('appNavigation.serverPowerOperations') }} </b-nav-item> </b-collapse> diff --git a/src/locales/en.json b/src/locales/en.json index 30bfc88d..0de52987 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -183,5 +183,27 @@ "errorRebootStart": "Error rebooting BMC.", "successRebootStart": "Rebooting BMC." } + }, + "pageServerPowerOperations": { + "currentStatus": "Current status", + "hostname": "Hostname", + "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", + "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", + "orderlyShutdown": "Orderly - OS shuts down, then server shuts down", + "powerOn": "Power on", + "reboot": "Reboot", + "rebootServer": "Reboot server", + "shutDown": "Shut down", + "shutdownServer": "Shutdown server", + "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" + } } }
\ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index dda4daf5..0d246cda 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -40,6 +40,14 @@ const routes = [ } }, { + path: '/control/server-power-operations', + name: 'server-power-operations', + component: () => import('@/views/Control/ServerPowerOperations'), + meta: { + title: 'appPageTitle.serverPowerOperations' + } + }, + { path: '/unauthorized', name: 'unauthorized', component: () => import('@/views/Unauthorized'), diff --git a/src/store/modules/Control/ControlStore.js b/src/store/modules/Control/ControlStore.js index 9b2e4592..6f9ced43 100644 --- a/src/store/modules/Control/ControlStore.js +++ b/src/store/modules/Control/ControlStore.js @@ -1,8 +1,45 @@ import api from '../../api'; import i18n from '../../../i18n'; +/** + * Watch for hostStatus changes in GlobalStore module + * to set isOperationInProgress state + * Stop watching status changes and resolve Promise when + * hostStatus value matches passed argument or after 5 minutes + * @param {string} hostStatus + * @returns {Promise} + */ +const checkForHostStatus = function(hostStatus) { + return new Promise(resolve => { + const timer = setTimeout(() => { + resolve(); + unwatch(); + }, 300000 /*5mins*/); + const unwatch = this.watch( + state => state.global.hostStatus, + value => { + if (value === hostStatus) { + resolve(); + unwatch(); + clearTimeout(timer); + } + } + ); + }); +}; + const ControlStore = { namespaced: true, + state: { + isOperationInProgress: false + }, + getters: { + isOperationInProgress: state => state.isOperationInProgress + }, + mutations: { + setOperationInProgress: (state, inProgress) => + (state.isOperationInProgress = inProgress) + }, actions: { async rebootBmc() { const data = { ResetType: 'GracefulRestart' }; @@ -13,6 +50,48 @@ const ControlStore = { console.log(error); throw new Error(i18n.t('pageRebootBmc.toast.errorRebootStart')); }); + }, + async hostPowerOn({ dispatch, commit }) { + const data = { ResetType: 'On' }; + dispatch('hostPowerChange', data); + await checkForHostStatus.bind(this, 'on')(); + commit('setOperationInProgress', false); + }, + async hostSoftReboot({ dispatch, commit }) { + const data = { ResetType: 'GracefulRestart' }; + dispatch('hostPowerChange', data); + await checkForHostStatus.bind(this, 'on')(); + commit('setOperationInProgress', false); + }, + async hostHardReboot({ dispatch, commit }) { + // TODO: Update when ForceWarmReboot property + // available + dispatch('hostPowerChange', { ResetType: 'ForceOff' }); + await checkForHostStatus.bind(this, 'off')(); + dispatch('hostPowerChange', { ResetType: 'On' }); + await checkForHostStatus.bind(this, 'on')(); + commit('setOperationInProgress', false); + }, + async hostSoftPowerOff({ dispatch, commit }) { + const data = { ResetType: 'GracefulShutdown' }; + dispatch('hostPowerChange', data); + await checkForHostStatus.bind(this, 'off')(); + commit('setOperationInProgress', false); + }, + async hostHardPowerOff({ dispatch, commit }) { + const data = { ResetType: 'ForceOff' }; + dispatch('hostPowerChange', data); + await checkForHostStatus.bind(this, 'off')(); + commit('setOperationInProgress', false); + }, + hostPowerChange({ commit }, data) { + commit('setOperationInProgress', true); + api + .post('/redfish/v1/Systems/system/Actions/ComputerSystem.Reset', data) + .catch(error => { + console.log(error); + commit('setOperationInProgress', false); + }); } } }; diff --git a/src/views/Control/ServerPowerOperations/ServerPowerOperations.vue b/src/views/Control/ServerPowerOperations/ServerPowerOperations.vue new file mode 100644 index 00000000..c9b02b3e --- /dev/null +++ b/src/views/Control/ServerPowerOperations/ServerPowerOperations.vue @@ -0,0 +1,184 @@ +<template> + <b-container fluid> + <page-title /> + <b-row> + <b-col md="8" lg="8" xl="6"> + <page-section + :section-title="$t('pageServerPowerOperations.currentStatus')" + > + <dl> + <dt>{{ $t('pageServerPowerOperations.hostname') }}</dt> + <dd>{{ hostname }}</dd> + </dl> + <dl> + <dt>{{ $t('pageServerPowerOperations.hostStatus') }}</dt> + <dd v-if="hostStatus === 'on'"> + {{ $t('global.status.on') }} + </dd> + <dd v-else-if="hostStatus === 'off'"> + {{ $t('global.status.off') }} + </dd> + <dd v-else> + {{ $t('global.status.notAvailable') }} + </dd> + </dl> + </page-section> + </b-col> + </b-row> + <b-row> + <b-col md="8" lg="7" xl="8"> + <page-section + :section-title="$t('pageServerPowerOperations.operations')" + > + <template v-if="isOperationInProgress"> + {{ $t('pageServerPowerOperations.operationInProgress') }} + </template> + <template v-else-if="hostStatus === 'off'"> + <b-button variant="primary" @click="powerOn"> + {{ $t('pageServerPowerOperations.powerOn') }} + </b-button> + </template> + <template v-else-if="hostStatus === 'on'"> + <!-- Reboot server options --> + <b-form novalidate class="mb-5" @submit.prevent="rebootServer"> + <b-form-group + :label="$t('pageServerPowerOperations.rebootServer')" + > + <b-form-radio + v-model="form.rebootOption" + name="reboot-option" + value="orderly" + > + {{ $t('pageServerPowerOperations.orderlyReboot') }} + </b-form-radio> + <b-form-radio + v-model="form.rebootOption" + name="reboot-option" + value="immediate" + > + {{ $t('pageServerPowerOperations.immediateReboot') }} + </b-form-radio> + </b-form-group> + <b-button variant="primary" type="submit"> + {{ $t('pageServerPowerOperations.reboot') }} + </b-button> + </b-form> + <!-- Shutdown server options --> + <b-form novalidate @submit.prevent="shutdownServer"> + <b-form-group + :label="$t('pageServerPowerOperations.shutdownServer')" + > + <b-form-radio + v-model="form.shutdownOption" + name="shutdown-option" + value="orderly" + > + {{ $t('pageServerPowerOperations.orderlyShutdown') }} + </b-form-radio> + <b-form-radio + v-model="form.shutdownOption" + name="shutdown-option" + value="immediate" + > + {{ $t('pageServerPowerOperations.immediateShutdown') }} + </b-form-radio> + </b-form-group> + <b-button variant="primary" type="submit"> + {{ $t('pageServerPowerOperations.shutDown') }} + </b-button> + </b-form> + </template> + <template v-else> + {{ $t('global.status.notAvailable') }} + </template> + </page-section> + </b-col> + </b-row> + </b-container> +</template> + +<script> +import PageTitle from '../../../components/Global/PageTitle'; +import PageSection from '../../../components/Global/PageSection'; +import BVToastMixin from '../../../components/Mixins/BVToastMixin'; + +export default { + name: 'ServerPowerOperations', + components: { PageTitle, PageSection }, + mixins: [BVToastMixin], + data() { + return { + form: { + rebootOption: 'orderly', + shutdownOption: 'orderly' + } + }; + }, + computed: { + hostStatus() { + return this.$store.getters['global/hostStatus']; + }, + hostname() { + return this.$store.getters['global/hostName']; + }, + isOperationInProgress() { + return this.$store.getters['controls/isOperationInProgress']; + } + }, + created() { + this.$store.dispatch('global/getHostName'); + }, + methods: { + powerOn() { + this.$store.dispatch('controls/hostPowerOn'); + }, + rebootServer() { + const modalMessage = this.$t( + 'pageServerPowerOperations.modal.confirmRebootMessage' + ); + const modalOptions = { + title: this.$t('pageServerPowerOperations.modal.confirmRebootTitle'), + okTitle: this.$t('global.action.confirm') + }; + + if (this.form.rebootOption === 'orderly') { + this.$bvModal + .msgBoxConfirm(modalMessage, modalOptions) + .then(confirmed => { + if (confirmed) this.$store.dispatch('controls/hostSoftReboot'); + }); + } else if (this.form.rebootOption === 'immediate') { + this.$bvModal + .msgBoxConfirm(modalMessage, modalOptions) + .then(confirmed => { + if (confirmed) this.$store.dispatch('controls/hostHardReboot'); + }); + } + }, + shutdownServer() { + const modalMessage = this.$t( + 'pageServerPowerOperations.modal.confirmShutdownMessage' + ); + const modalOptions = { + title: this.$t('pageServerPowerOperations.modal.confirmShutdownTitle'), + okTitle: this.$t('global.action.confirm') + }; + + if (this.form.shutdownOption === 'orderly') { + this.$bvModal + .msgBoxConfirm(modalMessage, modalOptions) + .then(confirmed => { + if (confirmed) this.$store.dispatch('controls/hostSoftPowerOff'); + }); + } + if (this.form.shutdownOption === 'immediate') { + this.$bvModal + .msgBoxConfirm(modalMessage, modalOptions) + .then(confirmed => { + if (confirmed) this.$store.dispatch('controls/hostHardPowerOff'); + }); + } + } + } +}; +</script> diff --git a/src/views/Control/ServerPowerOperations/index.js b/src/views/Control/ServerPowerOperations/index.js new file mode 100644 index 00000000..10430047 --- /dev/null +++ b/src/views/Control/ServerPowerOperations/index.js @@ -0,0 +1,2 @@ +import ServerPowerOperations from './ServerPowerOperations.vue'; +export default ServerPowerOperations; |