blob: 03f5af4c622a05a9d5ec7e60cfa42f079c6824e2 [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';
219import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
220import 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],
232 data() {
233 return {
234 isWorkstationSelected: true,
235 file: null,
236 tftpIpAddress: null,
237 tftpFileName: null,
Derick Montague602e98a2020-10-21 16:20:00 -0500238 timeoutId: null,
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700239 };
240 },
241 computed: {
242 hostStatus() {
243 return this.$store.getters['global/hostStatus'];
244 },
245 isHostOff() {
246 return this.hostStatus === 'off' ? true : false;
247 },
248 isOperationInProgress() {
249 return this.$store.getters['controls/isOperationInProgress'];
250 },
251 ...mapGetters('firmwareSingleImage', [
252 'backupFirmwareStatus',
253 'backupFirmwareVersion',
254 'isRebootFromBackupAvailable',
Derick Montague602e98a2020-10-21 16:20:00 -0500255 'systemFirmwareVersion',
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700256 ]),
257 isPageDisabled() {
258 return !this.isHostOff || this.loading || this.isOperationInProgress;
Derick Montague602e98a2020-10-21 16:20:00 -0500259 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700260 },
261 watch: {
Derick Montague602e98a2020-10-21 16:20:00 -0500262 isWorkstationSelected: function () {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700263 this.$v.$reset();
264 this.file = null;
265 this.tftpIpAddress = null;
266 this.tftpFileName = null;
Derick Montague602e98a2020-10-21 16:20:00 -0500267 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700268 },
269 created() {
270 this.startLoader();
271 this.$store.dispatch('firmwareSingleImage/getUpdateServiceApplyTime');
272 Promise.all([
273 this.$store.dispatch('global/getHostStatus'),
Derick Montague602e98a2020-10-21 16:20:00 -0500274 this.$store.dispatch('firmwareSingleImage/getFirmwareInformation'),
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700275 ]).finally(() => this.endLoader());
276 },
277 beforeRouteLeave(to, from, next) {
278 this.hideLoader();
279 this.clearRebootTimeout();
280 next();
281 },
282 validations() {
283 return {
284 file: {
Derick Montague602e98a2020-10-21 16:20:00 -0500285 required: requiredIf(function () {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700286 return this.isWorkstationSelected;
Derick Montague602e98a2020-10-21 16:20:00 -0500287 }),
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700288 },
289 tftpIpAddress: {
Derick Montague602e98a2020-10-21 16:20:00 -0500290 required: requiredIf(function () {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700291 return !this.isWorkstationSelected;
Derick Montague602e98a2020-10-21 16:20:00 -0500292 }),
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700293 },
294 tftpFileName: {
Derick Montague602e98a2020-10-21 16:20:00 -0500295 required: requiredIf(function () {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700296 return !this.isWorkstationSelected;
Derick Montague602e98a2020-10-21 16:20:00 -0500297 }),
298 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700299 };
300 },
301 methods: {
302 uploadFirmware() {
303 const startTime = this.$options.filters.formatTime(new Date());
304 this.setRebootTimeout(360000); //6 minute timeout
305 this.infoToast(
306 this.$t('pageFirmware.toast.infoUploadStartTimeMessage', { startTime }),
307 this.$t('pageFirmware.toast.infoUploadStartTimeTitle')
308 );
309 if (this.isWorkstationSelected) {
310 this.dispatchWorkstationUpload();
311 } else {
312 this.dispatchTftpUpload();
313 }
314 },
315 dispatchWorkstationUpload() {
316 this.$store
317 .dispatch('firmwareSingleImage/uploadFirmware', this.file)
Derick Montague602e98a2020-10-21 16:20:00 -0500318 .then((success) =>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700319 this.infoToast(
320 success,
321 this.$t('pageFirmware.toast.successUploadTitle')
322 )
323 )
324 .catch(({ message }) => {
325 this.errorToast(message);
326 this.clearRebootTimeout();
327 });
328 },
329 dispatchTftpUpload() {
330 const data = {
331 address: this.tftpIpAddress,
Derick Montague602e98a2020-10-21 16:20:00 -0500332 filename: this.tftpFileName,
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700333 };
334 this.$store
335 .dispatch('firmwareSingleImage/uploadFirmwareTFTP', data)
Derick Montague602e98a2020-10-21 16:20:00 -0500336 .then((success) =>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700337 this.infoToast(
338 success,
339 this.$t('pageFirmware.toast.successUploadTitle')
340 )
341 )
342 .catch(({ message }) => {
343 this.errorToast(message);
344 this.clearRebootTimeout();
345 });
346 },
347 rebootFromBackup() {
348 this.setRebootTimeout();
349 this.$store
350 .dispatch('firmwareSingleImage/switchFirmwareAndReboot')
Derick Montague602e98a2020-10-21 16:20:00 -0500351 .then((success) =>
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700352 this.infoToast(success, this.$t('global.status.success'))
353 )
354 .catch(({ message }) => {
355 this.errorToast(message);
356 this.clearRebootTimeout();
357 });
358 },
359 setRebootTimeout(timeoutMs = 60000) {
360 // Set a timeout to disable page interactions while
361 // an upload or BMC reboot is in progress
362 this.startLoader();
363 this.timeoutId = setTimeout(() => {
364 this.endLoader();
365 this.infoToast(
366 this.$t('pageFirmware.toast.infoRefreshApplicationMessage'),
367 this.$t('pageFirmware.toast.infoRefreshApplicationTitle')
368 );
369 }, timeoutMs);
370 },
371 clearRebootTimeout() {
372 if (this.timeoutId) {
373 clearTimeout(this.timeoutId);
374 this.endLoader();
375 }
376 },
377 onSubmitUpload() {
378 this.$v.$touch();
379 if (this.$v.$invalid) return;
380 this.$bvModal.show('modal-upload');
381 },
382 onClickShutDown() {
383 this.$bvModal
384 .msgBoxConfirm(this.$t('pageFirmware.modal.serverShutdownMessage'), {
385 title: this.$t('pageFirmware.modal.serverShutdownWillCauseOutage'),
386 okTitle: this.$t('pageFirmware.modal.shutDownServer'),
Derick Montague602e98a2020-10-21 16:20:00 -0500387 okVariant: 'danger',
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700388 })
Derick Montague602e98a2020-10-21 16:20:00 -0500389 .then((shutdownConfirmed) => {
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700390 if (shutdownConfirmed)
391 this.$store.dispatch('controls/hostSoftPowerOff');
392 });
Derick Montague602e98a2020-10-21 16:20:00 -0500393 },
394 },
Yoshie Muranaka0b980db2020-10-06 09:24:14 -0700395};
396</script>
397
398<style lang="scss" scoped>
399.update-code {
400 border-left: none;
401 @include media-breakpoint-up(xl) {
402 border-left: 1px solid gray('300');
403 }
404}
405</style>