blob: 426d5c253d34cdac7c246323c3247df479d42f56 [file] [log] [blame]
Yoshie Muranaka0b980db2020-10-06 09:24:14 -07001<template>
2 <b-container fluid="xl">
Yoshie Muranaka98bb24e2020-10-06 10:00:19 -07003 <page-title :description="$t('pageFirmware.pageDescriptionSingleImage')" />
Yoshie Muranaka0b980db2020-10-06 09:24:14 -07004 <!-- Operation in progress alert -->
5 <alert v-if="isOperationInProgress" variant="info" class="mb-5">
6 <p>
7 {{ $t('pageFirmware.alert.operationInProgress') }}
8 </p>
9 </alert>
10 <!-- Shutdown server warning alert -->
11 <alert v-else-if="!isHostOff" variant="warning" class="mb-5">
12 <p class="font-weight-bold mb-1">
13 {{ $t('pageFirmware.alert.serverShutdownRequiredBeforeUpdate') }}
14 </p>
15 {{ $t('pageFirmware.alert.serverShutdownRequiredInfo') }}
Derick Montague602e98a2020-10-21 16:20:00 -050016 <template #action>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -070017 <b-btn variant="link" class="text-nowrap" @click="onClickShutDown">
18 {{ $t('pageFirmware.alert.shutDownServer') }}
19 </b-btn>
20 </template>
21 </alert>
22 <b-row class="mb-4">
23 <!-- Firmware on system -->
24 <b-col md="10" lg="12" xl="8" class="pr-xl-4">
25 <page-section :section-title="$t('pageFirmware.firmwareOnSystem')">
26 <b-card-group deck>
27 <!-- Current FW -->
28 <b-card header-bg-variant="success">
Derick Montague602e98a2020-10-21 16:20:00 -050029 <template #header>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -070030 <dl class="mb-0">
31 <dt>{{ $t('pageFirmware.current') }}</dt>
32 <dd class="mb-0">{{ systemFirmwareVersion }}</dd>
33 </dl>
34 </template>
35 <b-row>
36 <b-col xs="6">
37 <dl class="my-0">
38 <dt>{{ $t('pageFirmware.bmcStatus') }}</dt>
39 <dd>{{ $t('pageFirmware.running') }}</dd>
40 </dl>
41 </b-col>
42 <b-col xs="6">
43 <dl class="my-0">
44 <dt>{{ $t('pageFirmware.hostStatus') }}</dt>
45 <dd v-if="hostStatus === 'on'">
46 {{ $t('global.status.on') }}
47 </dd>
48 <dd v-else-if="hostStatus === 'off'">
49 {{ $t('global.status.off') }}
50 </dd>
51 <dd v-else>
52 {{ $t('global.status.notAvailable') }}
53 </dd>
54 </dl>
55 </b-col>
56 </b-row>
57 </b-card>
58
59 <!-- Backup FW -->
60 <b-card>
Derick Montague602e98a2020-10-21 16:20:00 -050061 <template #header>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -070062 <dl class="mb-0">
63 <dt>{{ $t('pageFirmware.backup') }}</dt>
64 <dd class="mb-0">{{ backupFirmwareVersion }}</dd>
65 </dl>
66 </template>
67 <b-row>
68 <b-col xs="6">
69 <dl class="my-0">
70 <dt>{{ $t('pageFirmware.state') }}</dt>
71 <dd>{{ backupFirmwareStatus }}</dd>
72 </dl>
73 </b-col>
74 </b-row>
75 </b-card>
76 </b-card-group>
77 </page-section>
78
79 <!-- Change to backup image -->
80 <page-section :section-title="$t('pageFirmware.changeToBackupImage')">
81 <dl class="mb-5">
82 <dt>
83 {{ $t('pageFirmware.backupImage') }}
84 </dt>
85 <dd>{{ backupFirmwareVersion }}</dd>
86 </dl>
87 <b-btn
88 v-b-modal.modal-reboot-backup
89 type="button"
90 variant="primary"
91 :disabled="isPageDisabled || !isRebootFromBackupAvailable"
92 >
93 {{ $t('pageFirmware.changeAndRebootBmc') }}
94 </b-btn>
95 </page-section>
96 </b-col>
97
98 <!-- Update code -->
99 <b-col sm="8" xl="4" class="update-code pl-xl-4">
100 <page-section :section-title="$t('pageFirmware.updateCode')">
101 <b-form @submit.prevent="onSubmitUpload">
102 <b-form-group
103 :label="$t('pageFirmware.form.uploadLocation')"
104 :disabled="isPageDisabled"
105 >
106 <b-form-radio v-model="isWorkstationSelected" :value="true">
107 {{ $t('pageFirmware.form.workstation') }}
108 </b-form-radio>
109 <b-form-radio v-model="isWorkstationSelected" :value="false">
110 {{ $t('pageFirmware.form.tftpServer') }}
111 </b-form-radio>
112 </b-form-group>
113
114 <!-- Workstation Upload -->
115 <template v-if="isWorkstationSelected">
116 <b-form-group
117 :label="$t('pageFirmware.form.imageFile')"
118 label-for="image-file"
119 >
120 <b-form-text id="image-file-help-block">
121 {{ $t('pageFirmware.form.onlyTarFilesAccepted') }}
122 </b-form-text>
123 <b-form-file
124 id="image-file"
125 v-model="file"
126 accept=".tar"
127 aria-describedby="image-file-help-block"
128 :browse-text="$t('global.fileUpload.browseText')"
129 :drop-placeholder="$t('global.fileUpload.dropPlaceholder')"
130 :placeholder="$t('global.fileUpload.placeholder')"
131 :disabled="isPageDisabled"
132 :state="getValidationState($v.file)"
133 @input="$v.file.$touch()"
134 />
135 <b-form-invalid-feedback role="alert">
136 {{ $t('global.form.required') }}
137 </b-form-invalid-feedback>
138 </b-form-group>
139 </template>
140
141 <!-- TFTP Server Upload -->
142 <template v-else>
143 <b-form-group
144 :label="$t('pageFirmware.form.tftpServerAddress')"
145 label-for="tftp-ip"
146 >
147 <b-form-text id="server-address-help-block">
148 {{ $t('pageFirmware.form.tftpServerAddressHelper') }}
149 </b-form-text>
150 <b-form-input
151 id="tftp-id"
152 v-model="tftpIpAddress"
153 type="text"
154 :state="getValidationState($v.tftpIpAddress)"
155 :disabled="isPageDisabled"
156 aria-describedby="server-address-help-block"
157 @input="$v.tftpIpAddress.$touch()"
158 />
159 <b-form-invalid-feedback role="alert">
160 {{ $t('global.form.fieldRequired') }}
161 </b-form-invalid-feedback>
162 </b-form-group>
163 <b-form-group
164 :label="$t('pageFirmware.form.imageFileName')"
165 label-for="tftp-file-name"
166 >
167 <b-form-input
168 id="tftp-file-name"
169 v-model="tftpFileName"
170 type="text"
171 :state="getValidationState($v.tftpFileName)"
172 :disabled="isPageDisabled"
173 @input="$v.tftpFileName.$touch()"
174 />
175 <b-form-invalid-feedback role="alert">
176 {{ $t('global.form.fieldRequired') }}
177 </b-form-invalid-feedback>
178 </b-form-group>
179 </template>
180
181 <!-- Info alert -->
182 <alert variant="info" class="mt-4 mb-5">
183 <p class="font-weight-bold mb-1">
184 {{ $t('pageFirmware.alert.updateProcess') }}
185 </p>
Yoshie Muranaka98bb24e2020-10-06 10:00:19 -0700186 <p>{{ $t('pageFirmware.alert.updateProcessInfoSingleImage') }}</p>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700187 </alert>
188 <b-form-group>
189 <b-btn type="submit" variant="primary" :disabled="isPageDisabled">
190 {{ $t('pageFirmware.form.uploadAndRebootBmc') }}
191 </b-btn>
192 </b-form-group>
193 </b-form>
194 </page-section>
195 </b-col>
196 </b-row>
197
198 <!-- Modals -->
199 <modal-upload @ok="uploadFirmware" />
200 <modal-reboot-backup
201 :current="systemFirmwareVersion"
202 :backup="backupFirmwareVersion"
203 @ok="rebootFromBackup"
204 />
205 </b-container>
206</template>
207
208<script>
209import { requiredIf } from 'vuelidate/lib/validators';
210import { mapGetters } from 'vuex';
211
212import PageSection from '@/components/Global/PageSection';
213import PageTitle from '@/components/Global/PageTitle';
214import Alert from '@/components/Global/Alert';
215import ModalUpload from './FirmwareSingleImageModalUpload';
216import ModalRebootBackup from './FirmwareSingleImageModalRebootBackup';
217
218import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
Yoshie Muranakad73f4962020-12-09 08:52:23 -0800219import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin';
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700220import BVToastMixin from '@/components/Mixins/BVToastMixin';
221
222export default {
223 name: 'FirmwareSingleImage',
224 components: {
225 Alert,
226 ModalRebootBackup,
227 ModalUpload,
228 PageSection,
Derick Montague602e98a2020-10-21 16:20:00 -0500229 PageTitle,
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700230 },
231 mixins: [BVToastMixin, LoadingBarMixin, VuelidateMixin],
Derick Montagueefbd4012020-11-03 14:10:45 -0600232 beforeRouteLeave(to, from, next) {
233 this.hideLoader();
234 this.clearRebootTimeout();
235 next();
236 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700237 data() {
238 return {
239 isWorkstationSelected: true,
240 file: null,
241 tftpIpAddress: null,
242 tftpFileName: null,
Derick Montague602e98a2020-10-21 16:20:00 -0500243 timeoutId: null,
Yoshie Muranakad73f4962020-12-09 08:52:23 -0800244 loading,
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700245 };
246 },
247 computed: {
248 hostStatus() {
249 return this.$store.getters['global/hostStatus'];
250 },
251 isHostOff() {
252 return this.hostStatus === 'off' ? true : false;
253 },
254 isOperationInProgress() {
255 return this.$store.getters['controls/isOperationInProgress'];
256 },
257 ...mapGetters('firmwareSingleImage', [
258 'backupFirmwareStatus',
259 'backupFirmwareVersion',
260 'isRebootFromBackupAvailable',
Derick Montague602e98a2020-10-21 16:20:00 -0500261 'systemFirmwareVersion',
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700262 ]),
263 isPageDisabled() {
264 return !this.isHostOff || this.loading || this.isOperationInProgress;
Derick Montague602e98a2020-10-21 16:20:00 -0500265 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700266 },
267 watch: {
Derick Montague602e98a2020-10-21 16:20:00 -0500268 isWorkstationSelected: function () {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700269 this.$v.$reset();
270 this.file = null;
271 this.tftpIpAddress = null;
272 this.tftpFileName = null;
Derick Montague602e98a2020-10-21 16:20:00 -0500273 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700274 },
275 created() {
276 this.startLoader();
277 this.$store.dispatch('firmwareSingleImage/getUpdateServiceApplyTime');
278 Promise.all([
279 this.$store.dispatch('global/getHostStatus'),
Derick Montague602e98a2020-10-21 16:20:00 -0500280 this.$store.dispatch('firmwareSingleImage/getFirmwareInformation'),
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700281 ]).finally(() => this.endLoader());
282 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700283 validations() {
284 return {
285 file: {
Derick Montague602e98a2020-10-21 16:20:00 -0500286 required: requiredIf(function () {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700287 return this.isWorkstationSelected;
Derick Montague602e98a2020-10-21 16:20:00 -0500288 }),
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700289 },
290 tftpIpAddress: {
Derick Montague602e98a2020-10-21 16:20:00 -0500291 required: requiredIf(function () {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700292 return !this.isWorkstationSelected;
Derick Montague602e98a2020-10-21 16:20:00 -0500293 }),
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700294 },
295 tftpFileName: {
Derick Montague602e98a2020-10-21 16:20:00 -0500296 required: requiredIf(function () {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700297 return !this.isWorkstationSelected;
Derick Montague602e98a2020-10-21 16:20:00 -0500298 }),
299 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700300 };
301 },
302 methods: {
303 uploadFirmware() {
304 const startTime = this.$options.filters.formatTime(new Date());
305 this.setRebootTimeout(360000); //6 minute timeout
306 this.infoToast(
307 this.$t('pageFirmware.toast.infoUploadStartTimeMessage', { startTime }),
308 this.$t('pageFirmware.toast.infoUploadStartTimeTitle')
309 );
310 if (this.isWorkstationSelected) {
311 this.dispatchWorkstationUpload();
312 } else {
313 this.dispatchTftpUpload();
314 }
315 },
316 dispatchWorkstationUpload() {
317 this.$store
318 .dispatch('firmwareSingleImage/uploadFirmware', this.file)
Derick Montague602e98a2020-10-21 16:20:00 -0500319 .then((success) =>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700320 this.infoToast(
321 success,
322 this.$t('pageFirmware.toast.successUploadTitle')
323 )
324 )
325 .catch(({ message }) => {
326 this.errorToast(message);
327 this.clearRebootTimeout();
328 });
329 },
330 dispatchTftpUpload() {
331 const data = {
332 address: this.tftpIpAddress,
Derick Montague602e98a2020-10-21 16:20:00 -0500333 filename: this.tftpFileName,
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700334 };
335 this.$store
336 .dispatch('firmwareSingleImage/uploadFirmwareTFTP', data)
Derick Montague602e98a2020-10-21 16:20:00 -0500337 .then((success) =>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700338 this.infoToast(
339 success,
340 this.$t('pageFirmware.toast.successUploadTitle')
341 )
342 )
343 .catch(({ message }) => {
344 this.errorToast(message);
345 this.clearRebootTimeout();
346 });
347 },
348 rebootFromBackup() {
349 this.setRebootTimeout();
350 this.$store
351 .dispatch('firmwareSingleImage/switchFirmwareAndReboot')
Derick Montague602e98a2020-10-21 16:20:00 -0500352 .then((success) =>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700353 this.infoToast(success, this.$t('global.status.success'))
354 )
355 .catch(({ message }) => {
356 this.errorToast(message);
357 this.clearRebootTimeout();
358 });
359 },
360 setRebootTimeout(timeoutMs = 60000) {
361 // Set a timeout to disable page interactions while
362 // an upload or BMC reboot is in progress
363 this.startLoader();
364 this.timeoutId = setTimeout(() => {
365 this.endLoader();
366 this.infoToast(
367 this.$t('pageFirmware.toast.infoRefreshApplicationMessage'),
368 this.$t('pageFirmware.toast.infoRefreshApplicationTitle')
369 );
370 }, timeoutMs);
371 },
372 clearRebootTimeout() {
373 if (this.timeoutId) {
374 clearTimeout(this.timeoutId);
375 this.endLoader();
376 }
377 },
378 onSubmitUpload() {
379 this.$v.$touch();
380 if (this.$v.$invalid) return;
381 this.$bvModal.show('modal-upload');
382 },
383 onClickShutDown() {
384 this.$bvModal
385 .msgBoxConfirm(this.$t('pageFirmware.modal.serverShutdownMessage'), {
386 title: this.$t('pageFirmware.modal.serverShutdownWillCauseOutage'),
387 okTitle: this.$t('pageFirmware.modal.shutDownServer'),
Derick Montague602e98a2020-10-21 16:20:00 -0500388 okVariant: 'danger',
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700389 })
Derick Montague602e98a2020-10-21 16:20:00 -0500390 .then((shutdownConfirmed) => {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700391 if (shutdownConfirmed)
392 this.$store.dispatch('controls/hostSoftPowerOff');
393 });
Derick Montague602e98a2020-10-21 16:20:00 -0500394 },
395 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700396};
397</script>
398
399<style lang="scss" scoped>
400.update-code {
401 border-left: none;
402 @include media-breakpoint-up(xl) {
403 border-left: 1px solid gray('300');
404 }
405}
406</style>