summaryrefslogtreecommitdiff
path: root/src/views
diff options
context:
space:
mode:
authorYoshie Muranaka <yoshiemuranaka@gmail.com>2021-02-19 02:24:14 +0300
committerDerick Montague <derick.montague@ibm.com>2021-03-01 16:45:05 +0300
commit33d755f4e62beff72101f6ca07e4d31b04e13826 (patch)
treea67d890472f0c7f27951b8e86d472e220dac066e /src/views
parent9a25c80591e8872297f2c33ad9bcd6a97639f04c (diff)
downloadwebui-vue-33d755f4e62beff72101f6ca07e4d31b04e13826.tar.xz
Update the default firmware page
- Minor updates made to the general layout and styles - Changes to some page copy - Moves update firmware form to bottom of page - Adds dynamic TFTP upload option - Adds dynamic card layout for BMC and host firmwre - 2 cards for combined - 4 cards for separate - Removes FirmwareSingleImage components that were used for IBM builds Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com> Change-Id: Ib5465ecc30dd1505824bf41c82d33b7655d5e598
Diffstat (limited to 'src/views')
-rw-r--r--src/views/Configuration/Firmware/Firmware.vue391
-rw-r--r--src/views/Configuration/Firmware/FirmwareAlertServerPower.vue50
-rw-r--r--src/views/Configuration/Firmware/FirmwareCardsBmc.vue133
-rw-r--r--src/views/Configuration/Firmware/FirmwareCardsHost.vue73
-rw-r--r--src/views/Configuration/Firmware/FirmwareFormUpdate.vue204
-rw-r--r--src/views/Configuration/Firmware/FirmwareModalRebootBackupBmc.vue34
-rw-r--r--src/views/Configuration/Firmware/FirmwareModalSwitchToRunning.vue31
-rw-r--r--src/views/Configuration/Firmware/FirmwareModalUpdateFirmware.vue44
-rw-r--r--src/views/Configuration/Firmware/FirmwareModalUpload.vue20
-rw-r--r--src/views/Overview/Overview.vue28
10 files changed, 599 insertions, 409 deletions
diff --git a/src/views/Configuration/Firmware/Firmware.vue b/src/views/Configuration/Firmware/Firmware.vue
index 5001702a..e27c8a26 100644
--- a/src/views/Configuration/Firmware/Firmware.vue
+++ b/src/views/Configuration/Firmware/Firmware.vue
@@ -1,378 +1,93 @@
<template>
<b-container fluid="xl">
- <page-title :description="$t('pageFirmware.pageDescription')" />
- <b-row class="mb-4">
- <b-col md="10" lg="12" xl="8" class="pr-xl-4">
- <!-- Firmware on BMC -->
- <page-section :section-title="$t('pageFirmware.firmwareOnBmc')">
- <b-card-group deck>
- <!-- Current FW -->
- <b-card header-bg-variant="success">
- <template #header>
- <dl class="mb-0">
- <dt>{{ $t('pageFirmware.current') }}</dt>
- <dd class="mb-0">{{ bmcFirmwareCurrentVersion }}</dd>
- </dl>
- </template>
- <dl class="my-0">
- <dt>{{ $t('pageFirmware.state') }}:</dt>
- <dd>{{ bmcFirmwareCurrentState }}</dd>
- </dl>
- <template #footer></template>
- </b-card>
-
- <!-- Backup FW -->
- <b-card footer-class="p-0">
- <template #header>
- <dl class="mb-0">
- <dt>{{ $t('pageFirmware.backup') }}</dt>
- <dd class="mb-0">{{ bmcFirmwareBackupVersion }}</dd>
- </dl>
- </template>
- <dl class="my-0">
- <dt>{{ $t('pageFirmware.state') }}:</dt>
- <dd>{{ bmcFirmwareBackupState }}</dd>
- </dl>
- <template #footer>
- <b-btn
- v-b-modal.modal-reboot-backup-bmc
- :disabled="!bmcFirmwareBackupVersion"
- variant="link"
- size="sm"
- >
- <icon-switch class="d-none d-sm-inline-block" />
- {{ $t('pageFirmware.makeCurrentVersion') }}</b-btn
- >
- </template>
- </b-card>
- </b-card-group>
- </page-section>
-
- <!-- Firmware on Host -->
- <page-section :section-title="$t('pageFirmware.firmwareOnHost')">
- <b-card-group deck>
- <!-- Current FW -->
- <b-card header-bg-variant="success">
- <template #header>
- <dl class="mb-0">
- <dt>{{ $t('pageFirmware.current') }}</dt>
- <dd class="mb-0">{{ hostFirmwareCurrentVersion }}</dd>
- </dl>
- </template>
- <!-- State -->
- <dl class="my-0">
- <dt>{{ $t('pageFirmware.state') }}:</dt>
- <dd>{{ hostFirmwareCurrentState }}</dd>
- </dl>
- </b-card>
-
- <!-- Backup FW -->
- <b-card>
- <template #header>
- <dl class="mb-0">
- <dt>{{ $t('pageFirmware.backup') }}</dt>
- <dd class="mb-0">{{ hostFirmwareBackupVersion }}</dd>
- </dl>
- </template>
- <!-- State -->
- <dl class="my-0">
- <dt>{{ $t('pageFirmware.state') }}:</dt>
- <dd>{{ hostFirmwareBackupState }}</dd>
- </dl>
- </b-card>
- </b-card-group>
- </page-section>
- </b-col>
-
- <!-- Update code -->
- <b-col sm="8" xl="4" class="update-code pl-xl-4">
- <page-section :section-title="$t('pageFirmware.updateCode')">
- <b-form @submit.prevent="onSubmitUpload">
- <b-form-group :label="$t('pageFirmware.form.uploadLocation')">
- <b-form-radio v-model="isWorkstationSelected" :value="true">
- {{ $t('pageFirmware.form.workstation') }}
- </b-form-radio>
- <b-form-radio v-model="isWorkstationSelected" :value="false">
- {{ $t('pageFirmware.form.tftpServer') }}
- </b-form-radio>
- </b-form-group>
-
- <!-- Workstation Upload -->
- <template v-if="isWorkstationSelected">
- <b-form-group :label="$t('pageFirmware.form.imageFile')">
- <b-form-text id="image-file-help-block">
- {{ $t('pageFirmware.form.onlyTarFilesAccepted') }}
- </b-form-text>
- <form-file
- id="image-file"
- accept=".tar"
- :state="getValidationState($v.file)"
- aria-describedby="image-file-help-block"
- @input="onFileUpload($event)"
- >
- <template #invalid>
- <b-form-invalid-feedback role="alert">
- {{ $t('global.form.required') }}
- </b-form-invalid-feedback>
- </template>
- </form-file>
- </b-form-group>
- </template>
-
- <!-- TFTP Server Upload -->
- <template v-else>
- <b-form-group
- :label="$t('pageFirmware.form.tftpServerAddress')"
- label-for="tftp-ip"
- >
- <b-form-text id="server-address-help-block">
- {{ $t('pageFirmware.form.tftpServerAddressHelper') }}
- </b-form-text>
- <b-form-input
- id="tftp-id"
- v-model="tftpIpAddress"
- type="text"
- :state="getValidationState($v.tftpIpAddress)"
- aria-describedby="server-address-help-block"
- @input="$v.tftpIpAddress.$touch()"
- />
- <b-form-invalid-feedback role="alert">
- {{ $t('global.form.fieldRequired') }}
- </b-form-invalid-feedback>
- </b-form-group>
- <b-form-group
- :label="$t('pageFirmware.form.imageFileName')"
- label-for="tftp-file-name"
- >
- <b-form-input
- id="tftp-file-name"
- v-model="tftpFileName"
- type="text"
- :state="getValidationState($v.tftpFileName)"
- @input="$v.tftpFileName.$touch()"
- />
- <b-form-invalid-feedback role="alert">
- {{ $t('global.form.fieldRequired') }}
- </b-form-invalid-feedback>
- </b-form-group>
- </template>
+ <page-title />
+ <alerts-server-power
+ v-if="isServerPowerOffRequired"
+ :is-host-off="isHostOff"
+ />
- <!-- Info alert -->
- <alert variant="info" class="mt-4 mb-5">
- <p class="font-weight-bold mb-1">
- {{ $t('pageFirmware.alert.updateProcess') }}
- </p>
- <p>{{ $t('pageFirmware.alert.updateProcessInfo') }}</p>
- </alert>
+ <!-- Firmware cards -->
+ <b-row>
+ <b-col xl="10">
+ <!-- BMC Firmware -->
+ <bmc-cards :is-page-disabled="isPageDisabled" />
- <b-btn type="submit" variant="primary">
- {{ $t('pageFirmware.form.uploadAndRebootBmcOrHost') }}
- </b-btn>
- </b-form>
- </page-section>
+ <!-- Host Firmware -->
+ <host-cards v-if="!isSingleFileUploadEnabled" />
</b-col>
</b-row>
- <!-- Modals -->
- <modal-upload @ok="uploadFirmware" />
- <modal-reboot-backup-bmc
- :current="bmcFirmwareCurrentVersion || '--'"
- :backup="bmcFirmwareBackupVersion || '--'"
- @ok="switchBmcFirmware"
- />
+ <!-- Update firmware-->
+ <page-section
+ :section-title="$t('pageFirmware.sectionTitleUpdateFirmware')"
+ >
+ <b-row>
+ <b-col sm="8" md="6" xl="4">
+ <!-- Update form -->
+ <form-update
+ :is-host-off="isHostOff"
+ :is-page-disabled="isPageDisabled"
+ />
+ </b-col>
+ </b-row>
+ </page-section>
</b-container>
</template>
<script>
-import { requiredIf } from 'vuelidate/lib/validators';
-import { mapGetters } from 'vuex';
-import IconSwitch from '@carbon/icons-vue/es/arrows--horizontal/20';
-
+import AlertsServerPower from './FirmwareAlertServerPower';
+import BmcCards from './FirmwareCardsBmc';
+import FormUpdate from './FirmwareFormUpdate';
+import HostCards from './FirmwareCardsHost';
import PageSection from '@/components/Global/PageSection';
import PageTitle from '@/components/Global/PageTitle';
-import Alert from '@/components/Global/Alert';
-import ModalUpload from './FirmwareModalUpload';
-import ModalRebootBackupBmc from './FirmwareModalRebootBackupBmc';
-import FormFile from '@/components/Global/FormFile';
-import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin';
-import BVToastMixin from '@/components/Mixins/BVToastMixin';
export default {
- name: 'Firmware',
+ name: 'FirmwareSingleImage',
components: {
- Alert,
- IconSwitch,
- ModalRebootBackupBmc,
- ModalUpload,
+ AlertsServerPower,
+ BmcCards,
+ FormUpdate,
+ HostCards,
PageSection,
PageTitle,
- FormFile,
},
- mixins: [BVToastMixin, LoadingBarMixin, VuelidateMixin],
+ mixins: [LoadingBarMixin],
beforeRouteLeave(to, from, next) {
this.hideLoader();
- this.clearRebootTimeout();
next();
},
data() {
return {
- isWorkstationSelected: true,
- file: null,
- tftpIpAddress: null,
- tftpFileName: null,
- timeoutId: null,
- loading: loading,
+ loading,
+ isServerPowerOffRequired:
+ process.env.VUE_APP_SERVER_OFF_REQUIRED === 'true',
};
},
computed: {
- ...mapGetters('firmware', [
- 'bmcFirmwareCurrentVersion',
- 'bmcFirmwareCurrentState',
- 'bmcFirmwareBackupVersion',
- 'bmcFirmwareBackupState',
- 'hostFirmwareCurrentVersion',
- 'hostFirmwareCurrentState',
- 'hostFirmwareBackupVersion',
- 'hostFirmwareBackupState',
- ]),
- },
- watch: {
- isWorkstationSelected: function () {
- this.$v.$reset();
- this.file = null;
- this.tftpIpAddress = null;
- this.tftpFileName = null;
+ hostStatus() {
+ return this.$store.getters['global/hostStatus'];
+ },
+ isHostOff() {
+ return this.hostStatus === 'off' ? true : false;
+ },
+ isSingleFileUploadEnabled() {
+ return this.$store.getters['firmware/isSingleFileUploadEnabled'];
+ },
+ isPageDisabled() {
+ if (this.isServerPowerOffRequired) {
+ return !this.isHostOff || this.loading || this.isOperationInProgress;
+ }
+ return this.loading || this.isOperationInProgress;
},
},
created() {
this.startLoader();
- this.$store.dispatch('firmware/getUpdateServiceApplyTime');
this.$store
.dispatch('firmware/getFirmwareInformation')
.finally(() => this.endLoader());
},
- validations() {
- return {
- file: {
- required: requiredIf(function () {
- return this.isWorkstationSelected;
- }),
- },
- tftpIpAddress: {
- required: requiredIf(function () {
- return !this.isWorkstationSelected;
- }),
- },
- tftpFileName: {
- required: requiredIf(function () {
- return !this.isWorkstationSelected;
- }),
- },
- };
- },
- methods: {
- onFileUpload(file) {
- this.file = file;
- this.$v.file.$touch();
- },
- uploadFirmware() {
- const startTime = this.$options.filters.formatTime(new Date());
- this.setRebootTimeout(360000); //6 minute timeout
- this.infoToast(
- this.$t('pageFirmware.toast.infoUploadStartTimeMessage', { startTime }),
- { title: this.$t('pageFirmware.toast.infoUploadStartTimeTitle') }
- );
- if (this.isWorkstationSelected) {
- this.dispatchWorkstationUpload();
- } else {
- this.dispatchTftpUpload();
- }
- },
- dispatchWorkstationUpload() {
- this.$store
- .dispatch('firmware/uploadFirmware', this.file)
- .then((success) =>
- this.infoToast(success, {
- title: this.$t('pageFirmware.toast.successUploadTitle'),
- })
- )
- .catch(({ message }) => {
- this.errorToast(message);
- this.clearRebootTimeout();
- });
- },
- dispatchTftpUpload() {
- const data = {
- address: this.tftpIpAddress,
- filename: this.tftpFileName,
- };
- this.$store
- .dispatch('firmware/uploadFirmwareTFTP', data)
- .then((success) =>
- this.infoToast(success, {
- title: this.$t('pageFirmware.toast.successUploadTitle'),
- })
- )
- .catch(({ message }) => {
- this.errorToast(message);
- this.clearRebootTimeout();
- });
- },
- switchBmcFirmware() {
- this.setRebootTimeout();
- this.$store
- .dispatch('firmware/switchBmcFirmware')
- .then((success) =>
- this.infoToast(success, { title: this.$t('global.status.success') })
- )
- .catch(({ message }) => {
- this.errorToast(message);
- this.clearRebootTimeout();
- });
- },
- setRebootTimeout(timeoutMs = 60000) {
- // Set a timeout to disable page interactions while
- // an upload or BMC reboot is in progress
- this.startLoader();
- this.timeoutId = setTimeout(() => {
- this.endLoader();
- this.infoToast(
- this.$t('pageFirmware.toast.infoRefreshApplicationMessage'),
- {
- title: this.$t('pageFirmware.toast.infoRefreshApplicationTitle'),
- refreshAction: true,
- }
- );
- }, timeoutMs);
- },
- clearRebootTimeout() {
- if (this.timeoutId) {
- clearTimeout(this.timeoutId);
- this.endLoader();
- }
- },
- onSubmitUpload() {
- this.$v.$touch();
- if (this.$v.$invalid) return;
- this.$bvModal.show('modal-upload');
- },
- },
};
</script>
-
-<style lang="scss" scoped>
-.update-code {
- border-left: none;
- @include media-breakpoint-up(xl) {
- border-left: 1px solid gray('300');
- }
-}
-.card-footer {
- height: 40px;
-}
-.card-body {
- padding: 0.75rem 1.25rem;
-}
-</style>
diff --git a/src/views/Configuration/Firmware/FirmwareAlertServerPower.vue b/src/views/Configuration/Firmware/FirmwareAlertServerPower.vue
new file mode 100644
index 00000000..04713115
--- /dev/null
+++ b/src/views/Configuration/Firmware/FirmwareAlertServerPower.vue
@@ -0,0 +1,50 @@
+<template>
+ <b-row>
+ <b-col xl="10">
+ <!-- Operation in progress alert -->
+ <alert v-if="isOperationInProgress" variant="info" class="mb-5">
+ <p>
+ {{ $t('pageFirmware.alert.operationInProgress') }}
+ </p>
+ </alert>
+ <!-- Power off server warning alert -->
+ <alert v-else-if="!isHostOff" variant="warning" class="mb-5">
+ <p class="mb-0">
+ {{ $t('pageFirmware.alert.serverMustBePoweredOffTo') }}
+ </p>
+ <ul class="m-0">
+ <li>
+ {{ $t('pageFirmware.alert.switchRunningAndBackupImages') }}
+ </li>
+ <li>
+ {{ $t('pageFirmware.alert.updateFirmware') }}
+ </li>
+ </ul>
+ <template #action>
+ <b-link to="/control/server-power-operations">
+ {{ $t('pageFirmware.alert.viewServerPowerOperations') }}
+ </b-link>
+ </template>
+ </alert>
+ </b-col>
+ </b-row>
+</template>
+
+<script>
+import Alert from '@/components/Global/Alert';
+
+export default {
+ components: { Alert },
+ props: {
+ isHostOff: {
+ required: true,
+ type: Boolean,
+ },
+ },
+ computed: {
+ isOperationInProgress() {
+ return this.$store.getters['controls/isOperationInProgress'];
+ },
+ },
+};
+</script>
diff --git a/src/views/Configuration/Firmware/FirmwareCardsBmc.vue b/src/views/Configuration/Firmware/FirmwareCardsBmc.vue
new file mode 100644
index 00000000..2f038b9e
--- /dev/null
+++ b/src/views/Configuration/Firmware/FirmwareCardsBmc.vue
@@ -0,0 +1,133 @@
+<template>
+ <div>
+ <page-section :section-title="sectionTitle">
+ <b-card-group deck>
+ <!-- Running image -->
+ <b-card>
+ <template #header>
+ <p class="font-weight-bold m-0">
+ {{ $t('pageFirmware.cardTitleRunning') }}
+ </p>
+ </template>
+ <dl class="mb-0">
+ <dt>{{ $t('pageFirmware.cardBodyVersion') }}</dt>
+ <dd class="mb-0">{{ runningVersion }}</dd>
+ </dl>
+ </b-card>
+
+ <!-- Backup image -->
+ <b-card>
+ <template #header>
+ <p class="font-weight-bold m-0">
+ {{ $t('pageFirmware.cardTitleBackup') }}
+ </p>
+ </template>
+ <dl>
+ <dt>{{ $t('pageFirmware.cardBodyVersion') }}</dt>
+ <dd>
+ <status-icon v-if="showBackupImageStatus" status="danger" />
+ <span v-if="showBackupImageStatus" class="sr-only">
+ {{ backupStatus }}
+ </span>
+ {{ backupVersion }}
+ </dd>
+ </dl>
+ <b-btn
+ v-b-modal.modal-switch-to-running
+ data-test-id="firmware-button-switchToRunning"
+ variant="link"
+ size="sm"
+ class="py-0 px-1 mt-2"
+ :disabled="isPageDisabled || !backup"
+ >
+ <icon-switch class="d-none d-sm-inline-block" />
+ {{ $t('pageFirmware.cardActionSwitchToRunning') }}
+ </b-btn>
+ </b-card>
+ </b-card-group>
+ </page-section>
+ <modal-switch-to-running :backup="backupVersion" @ok="switchToRunning" />
+ </div>
+</template>
+
+<script>
+import IconSwitch from '@carbon/icons-vue/es/arrows--horizontal/20';
+import PageSection from '@/components/Global/PageSection';
+import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin';
+import BVToastMixin from '@/components/Mixins/BVToastMixin';
+
+import ModalSwitchToRunning from './FirmwareModalSwitchToRunning';
+
+export default {
+ components: { IconSwitch, ModalSwitchToRunning, PageSection },
+ mixins: [BVToastMixin, LoadingBarMixin],
+ props: {
+ isPageDisabled: {
+ required: true,
+ type: Boolean,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ loading,
+ };
+ },
+ computed: {
+ isSingleFileUploadEnabled() {
+ return this.$store.getters['firmware/isSingleFileUploadEnabled'];
+ },
+ sectionTitle() {
+ if (this.isSingleFileUploadEnabled) {
+ return this.$t('pageFirmware.sectionTitleBmcCardsCombined');
+ }
+ return this.$t('pageFirmware.sectionTitleBmcCards');
+ },
+ running() {
+ return this.$store.getters['firmware/activeBmcFirmware'];
+ },
+ backup() {
+ return this.$store.getters['firmware/backupBmcFirmware'];
+ },
+ runningVersion() {
+ return this.running?.version || '--';
+ },
+ backupVersion() {
+ return this.backup?.version || '--';
+ },
+ backupStatus() {
+ return this.backup?.status || null;
+ },
+ showBackupImageStatus() {
+ return (
+ this.backupStatus === 'Critical' || this.backupStatus === 'Warning'
+ );
+ },
+ },
+ methods: {
+ switchToRunning() {
+ this.startLoader();
+ const timerId = setTimeout(() => {
+ this.endLoader();
+ this.infoToast(this.$t('pageFirmware.toast.verifySwitchMessage'), {
+ title: this.$t('pageFirmware.toast.verifySwitch'),
+ refreshAction: true,
+ });
+ }, 60000);
+
+ this.$store
+ .dispatch('firmware/switchBmcFirmwareAndReboot')
+ .then(() =>
+ this.infoToast(this.$t('pageFirmware.toast.rebootStartedMessage'), {
+ title: this.$t('pageFirmware.toast.rebootStarted'),
+ })
+ )
+ .catch(({ message }) => {
+ this.errorToast(message);
+ clearTimeout(timerId);
+ this.endLoader();
+ });
+ },
+ },
+};
+</script>
diff --git a/src/views/Configuration/Firmware/FirmwareCardsHost.vue b/src/views/Configuration/Firmware/FirmwareCardsHost.vue
new file mode 100644
index 00000000..b4a8e90d
--- /dev/null
+++ b/src/views/Configuration/Firmware/FirmwareCardsHost.vue
@@ -0,0 +1,73 @@
+<template>
+ <page-section :section-title="$t('pageFirmware.sectionTitleHostCards')">
+ <b-card-group deck>
+ <!-- Running image -->
+ <b-card>
+ <template #header>
+ <p class="font-weight-bold m-0">
+ {{ $t('pageFirmware.cardTitleRunning') }}
+ </p>
+ </template>
+ <dl class="mb-0">
+ <dt>{{ $t('pageFirmware.cardBodyVersion') }}</dt>
+ <dd class="mb-0">{{ runningVersion }}</dd>
+ </dl>
+ </b-card>
+
+ <!-- Backup image -->
+ <b-card>
+ <template #header>
+ <p class="font-weight-bold m-0">
+ {{ $t('pageFirmware.cardTitleBackup') }}
+ </p>
+ </template>
+ <dl class="mb-0">
+ <dt>{{ $t('pageFirmware.cardBodyVersion') }}</dt>
+ <dd class="mb-0">
+ <status-icon v-if="showBackupImageStatus" status="danger" />
+ <span v-if="showBackupImageStatus" class="sr-only">
+ {{ backupStatus }}
+ </span>
+ {{ backupVersion }}
+ </dd>
+ </dl>
+ </b-card>
+ </b-card-group>
+ </page-section>
+</template>
+
+<script>
+import PageSection from '@/components/Global/PageSection';
+
+export default {
+ components: { PageSection },
+ computed: {
+ running() {
+ return this.$store.getters['firmware/activeHostFirmware'];
+ },
+ backup() {
+ return this.$store.getters['firmware/backupHostFirmware'];
+ },
+ runningVersion() {
+ return this.running?.version || '--';
+ },
+ backupVersion() {
+ return this.backup?.version || '--';
+ },
+ backupStatus() {
+ return this.backup?.status || null;
+ },
+ showBackupImageStatus() {
+ return (
+ this.backupStatus === 'Critical' || this.backupStatus === 'Warning'
+ );
+ },
+ },
+};
+</script>
+
+<style lang="scss" scoped>
+.page-section {
+ margin-top: -$spacer * 1.5;
+}
+</style>
diff --git a/src/views/Configuration/Firmware/FirmwareFormUpdate.vue b/src/views/Configuration/Firmware/FirmwareFormUpdate.vue
new file mode 100644
index 00000000..9f67e8d0
--- /dev/null
+++ b/src/views/Configuration/Firmware/FirmwareFormUpdate.vue
@@ -0,0 +1,204 @@
+<template>
+ <div>
+ <div class="form-background p-3">
+ <b-form @submit.prevent="onSubmitUpload">
+ <b-form-group
+ v-if="isTftpUploadAvailable"
+ :label="$t('pageFirmware.form.updateFirmware.fileSource')"
+ :disabled="isPageDisabled"
+ >
+ <b-form-radio v-model="isWorkstationSelected" :value="true">
+ {{ $t('pageFirmware.form.updateFirmware.workstation') }}
+ </b-form-radio>
+ <b-form-radio v-model="isWorkstationSelected" :value="false">
+ {{ $t('pageFirmware.form.updateFirmware.tftpServer') }}
+ </b-form-radio>
+ </b-form-group>
+
+ <!-- Workstation Upload -->
+ <template v-if="isWorkstationSelected">
+ <b-form-group
+ :label="$t('pageFirmware.form.updateFirmware.imageFile')"
+ label-for="image-file"
+ >
+ <b-form-text id="image-file-help-block">
+ {{ $t('pageFirmware.form.updateFirmware.imageFileHelperText') }}
+ </b-form-text>
+ <form-file
+ id="image-file"
+ accept=".tar"
+ :disabled="isPageDisabled"
+ :state="getValidationState($v.file)"
+ aria-describedby="image-file-help-block"
+ @input="onFileUpload($event)"
+ >
+ <template #invalid>
+ <b-form-invalid-feedback role="alert">
+ {{ $t('global.form.required') }}
+ </b-form-invalid-feedback>
+ </template>
+ </form-file>
+ </b-form-group>
+ </template>
+
+ <!-- TFTP Server Upload -->
+ <template v-else>
+ <b-form-group
+ :label="$t('pageFirmware.form.updateFirmware.fileAddress')"
+ label-for="tftp-address"
+ >
+ <b-form-input
+ id="tftp-address"
+ v-model="tftpFileAddress"
+ type="text"
+ :state="getValidationState($v.tftpFileAddress)"
+ :disabled="isPageDisabled"
+ @input="$v.tftpFileAddress.$touch()"
+ />
+ <b-form-invalid-feedback role="alert">
+ {{ $t('global.form.fieldRequired') }}
+ </b-form-invalid-feedback>
+ </b-form-group>
+ </template>
+ <b-btn
+ data-test-id="firmware-button-startUpdate"
+ type="submit"
+ variant="primary"
+ :disabled="isPageDisabled"
+ >
+ {{ $t('pageFirmware.form.updateFirmware.startUpdate') }}
+ </b-btn>
+ <alert
+ v-if="isServerPowerOffRequired && !isHostOff"
+ variant="warning"
+ :small="true"
+ class="mt-4"
+ >
+ <p class="col-form-label">
+ {{
+ $t('pageFirmware.alert.serverMustBePoweredOffToUpdateFirmware')
+ }}
+ </p>
+ </alert>
+ </b-form>
+ </div>
+
+ <!-- Modals -->
+ <modal-update-firmware @ok="updateFirmware" />
+ </div>
+</template>
+
+<script>
+import { requiredIf } from 'vuelidate/lib/validators';
+
+import BVToastMixin from '@/components/Mixins/BVToastMixin';
+import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin';
+import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
+
+import Alert from '@/components/Global/Alert';
+import FormFile from '@/components/Global/FormFile';
+import ModalUpdateFirmware from './FirmwareModalUpdateFirmware';
+
+export default {
+ components: { Alert, FormFile, ModalUpdateFirmware },
+ mixins: [BVToastMixin, LoadingBarMixin, VuelidateMixin],
+ props: {
+ isPageDisabled: {
+ required: true,
+ type: Boolean,
+ default: false,
+ },
+ isHostOff: {
+ required: true,
+ type: Boolean,
+ },
+ },
+ data() {
+ return {
+ loading,
+ isWorkstationSelected: true,
+ file: null,
+ tftpFileAddress: null,
+ isServerPowerOffRequired:
+ process.env.VUE_APP_SERVER_OFF_REQUIRED === 'true',
+ };
+ },
+ computed: {
+ isTftpUploadAvailable() {
+ return this.$store.getters['firmware/isTftpUploadAvailable'];
+ },
+ },
+ watch: {
+ isWorkstationSelected: function () {
+ this.$v.$reset();
+ this.file = null;
+ this.tftpFileAddress = null;
+ },
+ },
+ validations() {
+ return {
+ file: {
+ required: requiredIf(function () {
+ return this.isWorkstationSelected;
+ }),
+ },
+ tftpFileAddress: {
+ required: requiredIf(function () {
+ return !this.isWorkstationSelected;
+ }),
+ },
+ };
+ },
+ created() {
+ this.$store.dispatch('firmware/getUpdateServiceSettings');
+ },
+ methods: {
+ updateFirmware() {
+ this.startLoader();
+ const timerId = setTimeout(() => {
+ this.endLoader();
+ this.infoToast(this.$t('pageFirmware.toast.verifyUpdateMessage'), {
+ title: this.$t('pageFirmware.toast.verifyUpdate'),
+ refreshAction: true,
+ });
+ }, 360000);
+ this.infoToast(this.$t('pageFirmware.toast.updateStartedMessage'), {
+ title: this.$t('pageFirmware.toast.updateStarted'),
+ timestamp: true,
+ });
+ if (this.isWorkstationSelected) {
+ this.dispatchWorkstationUpload(timerId);
+ } else {
+ this.dispatchTftpUpload(timerId);
+ }
+ },
+ dispatchWorkstationUpload(timerId) {
+ this.$store
+ .dispatch('firmware/uploadFirmware', this.file)
+ .catch(({ message }) => {
+ this.endLoader();
+ this.errorToast(message);
+ clearTimeout(timerId);
+ });
+ },
+ dispatchTftpUpload(timerId) {
+ this.$store
+ .dispatch('firmware/uploadFirmwareTFTP', this.tftpFileAddress)
+ .catch(({ message }) => {
+ this.endLoader();
+ this.errorToast(message);
+ clearTimeout(timerId);
+ });
+ },
+ onSubmitUpload() {
+ this.$v.$touch();
+ if (this.$v.$invalid) return;
+ this.$bvModal.show('modal-update-firmware');
+ },
+ onFileUpload(file) {
+ this.file = file;
+ this.$v.file.$touch();
+ },
+ },
+};
+</script>
diff --git a/src/views/Configuration/Firmware/FirmwareModalRebootBackupBmc.vue b/src/views/Configuration/Firmware/FirmwareModalRebootBackupBmc.vue
deleted file mode 100644
index 305bb6cb..00000000
--- a/src/views/Configuration/Firmware/FirmwareModalRebootBackupBmc.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-<template>
- <b-modal
- id="modal-reboot-backup-bmc"
- :ok-title="$t('pageFirmware.modal.rebootFromBackup.primaryAction')"
- :cancel-title="$t('global.action.cancel')"
- :title="$t('pageFirmware.modal.rebootFromBackup.title')"
- @ok="$emit('ok')"
- >
- <p>
- {{ $t('pageFirmware.modal.rebootFromBackup.message1', { backup }) }}
- </p>
- <p>
- {{ $t('pageFirmware.modal.rebootFromBackup.message2', { current }) }}
- </p>
- <p class="font-weight-bold">
- {{ $t('pageFirmware.modal.rebootFromBackup.message3', { backup }) }}
- </p>
- </b-modal>
-</template>
-
-<script>
-export default {
- props: {
- current: {
- type: String,
- required: true,
- },
- backup: {
- type: String,
- required: true,
- },
- },
-};
-</script>
diff --git a/src/views/Configuration/Firmware/FirmwareModalSwitchToRunning.vue b/src/views/Configuration/Firmware/FirmwareModalSwitchToRunning.vue
new file mode 100644
index 00000000..dc4a4973
--- /dev/null
+++ b/src/views/Configuration/Firmware/FirmwareModalSwitchToRunning.vue
@@ -0,0 +1,31 @@
+<template>
+ <b-modal
+ id="modal-switch-to-running"
+ :ok-title="$t('pageFirmware.modal.switchImages')"
+ :cancel-title="$t('global.action.cancel')"
+ :title="$t('pageFirmware.modal.switchRunningImage')"
+ @ok="$emit('ok')"
+ >
+ <p>
+ {{ $t('pageFirmware.modal.switchRunningImageInfo') }}
+ </p>
+ <p class="m-0">
+ {{
+ $t('pageFirmware.modal.switchRunningImageInfo2', {
+ backup,
+ })
+ }}
+ </p>
+ </b-modal>
+</template>
+
+<script>
+export default {
+ props: {
+ backup: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
diff --git a/src/views/Configuration/Firmware/FirmwareModalUpdateFirmware.vue b/src/views/Configuration/Firmware/FirmwareModalUpdateFirmware.vue
new file mode 100644
index 00000000..18355217
--- /dev/null
+++ b/src/views/Configuration/Firmware/FirmwareModalUpdateFirmware.vue
@@ -0,0 +1,44 @@
+<template>
+ <b-modal
+ id="modal-update-firmware"
+ :title="$t('pageFirmware.sectionTitleUpdateFirmware')"
+ :ok-title="$t('pageFirmware.form.updateFirmware.startUpdate')"
+ :cancel-title="$t('global.action.cancel')"
+ @ok="$emit('ok')"
+ >
+ <template v-if="isSingleFileUploadEnabled">
+ <p>
+ {{ $t('pageFirmware.modal.updateFirmwareInfo') }}
+ </p>
+ <p>
+ {{
+ $t('pageFirmware.modal.updateFirmwareInfo2', {
+ running: runningBmcVersion,
+ })
+ }}
+ </p>
+ <p class="m-0">
+ {{ $t('pageFirmware.modal.updateFirmwareInfo3') }}
+ </p>
+ </template>
+ <template v-else>
+ {{ $t('pageFirmware.modal.updateFirmwareInfoDefault') }}
+ </template>
+ </b-modal>
+</template>
+
+<script>
+export default {
+ computed: {
+ runningBmc() {
+ return this.$store.getters['firmware/activeBmcFirmware'];
+ },
+ runningBmcVersion() {
+ return this.runningBmc?.version || '--';
+ },
+ isSingleFileUploadEnabled() {
+ return this.$store.getters['firmware/isSingleFileUploadEnabled'];
+ },
+ },
+};
+</script>
diff --git a/src/views/Configuration/Firmware/FirmwareModalUpload.vue b/src/views/Configuration/Firmware/FirmwareModalUpload.vue
deleted file mode 100644
index 3425904f..00000000
--- a/src/views/Configuration/Firmware/FirmwareModalUpload.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-<template>
- <b-modal
- id="modal-upload"
- ok-variant="danger"
- :title="$t('pageFirmware.modal.uploadAndRebootBmcOrHost.title')"
- :ok-title="$t('pageFirmware.modal.uploadAndRebootBmcOrHost.primaryAction')"
- :cancel-title="$t('global.action.cancel')"
- @ok="$emit('ok')"
- >
- <p>
- {{ $t('pageFirmware.modal.uploadAndRebootBmcOrHost.message1') }}
- </p>
- <p>
- {{ $t('pageFirmware.modal.uploadAndRebootBmcOrHost.message2') }}
- </p>
- <p class="font-weight-bold">
- {{ $t('pageFirmware.modal.uploadAndRebootBmcOrHost.message3') }}
- </p>
- </b-modal>
-</template>
diff --git a/src/views/Overview/Overview.vue b/src/views/Overview/Overview.vue
index 1d2da441..2436e393 100644
--- a/src/views/Overview/Overview.vue
+++ b/src/views/Overview/Overview.vue
@@ -104,13 +104,6 @@ export default {
PageSection,
},
mixins: [LoadingBarMixin],
- data() {
- return {
- firmwareStoreModuleName: this.$store.hasModule('firmwareSingleImage')
- ? 'firmwareSingleImage'
- : 'firmware',
- };
- },
computed: {
...mapState({
server: (state) => state.system.systems[0],
@@ -129,15 +122,18 @@ export default {
if (this.server) return this.server.serialNumber || '--';
return '--';
},
- hostFirmwareVersion() {
- if (this.server) return this.server.firmwareVersion || '--';
- return '--';
- },
}),
+ activeHostFirmware() {
+ return this.$store.getters[`firmware/activeHostFirmware`];
+ },
+ hostFirmwareVersion() {
+ return this.activeHostFirmware?.version || '--';
+ },
+ activeBmcFirmware() {
+ return this.$store.getters[`firmware/activeBmcFirmware`];
+ },
bmcFirmwareVersion() {
- return this.$store.getters[
- `${this.firmwareStoreModuleName}/bmcFirmwareCurrentVersion`
- ];
+ return this.activeBmcFirmware?.version || '--';
},
},
created() {
@@ -153,9 +149,7 @@ export default {
});
Promise.all([
this.$store.dispatch('system/getSystem'),
- this.$store.dispatch(
- `${this.firmwareStoreModuleName}/getFirmwareInformation`
- ),
+ this.$store.dispatch(`firmware/getFirmwareInformation`),
this.$store.dispatch('powerControl/getPowerControl'),
quicklinksPromise,
networkPromise,