xref: /openbmc/webui-vue/src/views/Operations/VirtualMedia/VirtualMedia.vue (revision d36ac8a8be8636ddd0e64ce005d507b21bcdeb00)
1<template>
2  <b-container fluid="xl">
3    <page-title />
4    <b-row class="mb-4">
5      <b-col md="12">
6        <page-section
7          :section-title="$t('pageVirtualMedia.virtualMediaSubTitleFirst')"
8        >
9          <b-row>
10            <b-col v-for="(dev, $index) in proxyDevices" :key="$index" md="6">
11              <b-form-group :label="dev.id" label-class="bold">
12                <form-file
13                  v-if="!dev.isActive"
14                  :id="concatId(dev.id)"
15                  v-model="dev.file"
16                >
17                  <template #invalid>
18                    <b-form-invalid-feedback role="alert">
19                      {{ $t('global.form.required') }}
20                    </b-form-invalid-feedback>
21                  </template>
22                </form-file>
23              </b-form-group>
24              <b-button
25                v-if="!dev.isActive"
26                variant="primary"
27                :disabled="!dev.file"
28                @click="startVM(dev)"
29              >
30                {{ $t('pageVirtualMedia.start') }}
31              </b-button>
32              <b-button
33                v-if="dev.isActive"
34                variant="primary"
35                :disabled="!dev.file"
36                @click="stopVM(dev)"
37              >
38                {{ $t('pageVirtualMedia.stop') }}
39              </b-button>
40            </b-col>
41          </b-row>
42        </page-section>
43      </b-col>
44    </b-row>
45    <b-row v-if="loadImageFromExternalServer" class="mb-4">
46      <b-col md="12">
47        <page-section
48          :section-title="$t('pageVirtualMedia.virtualMediaSubTitleSecond')"
49        >
50          <b-row>
51            <b-col
52              v-for="(device, $index) in legacyDevices"
53              :key="$index"
54              md="6"
55            >
56              <b-form-group
57                :label="device.id"
58                :label-for="device.id"
59                label-class="bold"
60              >
61                <b-button
62                  variant="primary"
63                  :disabled="device.isActive"
64                  @click="configureConnection(device)"
65                >
66                  {{ $t('pageVirtualMedia.configureConnection') }}
67                </b-button>
68
69                <b-button
70                  v-if="!device.isActive"
71                  variant="primary"
72                  class="float-end"
73                  :disabled="!device.serverUri"
74                  @click="startLegacy(device)"
75                >
76                  {{ $t('pageVirtualMedia.start') }}
77                </b-button>
78                <b-button
79                  v-if="device.isActive"
80                  variant="primary"
81                  class="float-end"
82                  @click="stopLegacy(device)"
83                >
84                  {{ $t('pageVirtualMedia.stop') }}
85                </b-button>
86              </b-form-group>
87            </b-col>
88          </b-row>
89        </page-section>
90      </b-col>
91    </b-row>
92    <modal-configure-connection
93      v-model="showConfigureConnectionModal"
94      :connection="modalConfigureConnection"
95      @ok="saveConnection"
96    />
97  </b-container>
98</template>
99
100<script>
101import PageTitle from '@/components/Global/PageTitle';
102import PageSection from '@/components/Global/PageSection';
103import BVToastMixin from '@/components/Mixins/BVToastMixin';
104import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
105import ModalConfigureConnection from './ModalConfigureConnection';
106import NbdServer from '@/utilities/NBDServer';
107import FormFile from '@/components/Global/FormFile';
108import { useI18n } from 'vue-i18n';
109import i18n from '@/i18n';
110import { useModal } from 'bootstrap-vue-next';
111
112export default {
113  name: 'VirtualMedia',
114  components: { PageTitle, PageSection, ModalConfigureConnection, FormFile },
115  mixins: [BVToastMixin, LoadingBarMixin],
116  setup() {
117    const bvModal = useModal();
118    return { bvModal };
119  },
120  data() {
121    return {
122      $t: useI18n().t,
123      modalConfigureConnection: null,
124      showConfigureConnectionModal: false,
125      loadImageFromExternalServer:
126        process.env.VUE_APP_VIRTUAL_MEDIA_LIST_ENABLED === 'true'
127          ? true
128          : false,
129    };
130  },
131  computed: {
132    proxyDevices() {
133      return this.$store.getters['virtualMedia/proxyDevices'];
134    },
135    legacyDevices() {
136      return this.$store.getters['virtualMedia/legacyDevices'];
137    },
138  },
139  created() {
140    this.$store.dispatch('global/getSystemInfo');
141    if (this.proxyDevices.length > 0 || this.legacyDevices.length > 0) return;
142    this.startLoader();
143    this.$store
144      .dispatch('virtualMedia/getData')
145      .finally(() => this.endLoader());
146  },
147  methods: {
148    startVM(device) {
149      const token = this.$store.getters['authentication/token'];
150      device.nbd = new NbdServer(
151        `wss://${window.location.host}${device.websocket}`,
152        device.file,
153        device.id,
154        token,
155      );
156      device.nbd.socketStarted = () =>
157        this.successToast(
158          i18n.global.t('pageVirtualMedia.toast.serverRunning'),
159        );
160      device.nbd.errorReadingFile = () =>
161        this.errorToast(
162          i18n.global.t('pageVirtualMedia.toast.errorReadingFile'),
163        );
164      device.nbd.socketClosed = (code) => {
165        if (code === 1000)
166          this.successToast(
167            i18n.global.t('pageVirtualMedia.toast.serverClosedSuccessfully'),
168          );
169        else
170          this.errorToast(
171            i18n.global.t('pageVirtualMedia.toast.serverClosedWithErrors'),
172          );
173        device.file = null;
174        device.isActive = false;
175      };
176
177      device.nbd.start();
178      device.isActive = true;
179    },
180    stopVM(device) {
181      device.nbd.stop();
182    },
183    startLegacy(connectionData) {
184      var data = {};
185      data.Image = connectionData.serverUri;
186      data.UserName = connectionData.username;
187      data.Password = connectionData.password;
188      data.WriteProtected = !connectionData.isRW;
189      this.startLoader();
190      this.$store
191        .dispatch('virtualMedia/mountImage', {
192          id: connectionData.id,
193          data: data,
194        })
195        .then(() => {
196          this.successToast(
197            i18n.global.t('pageVirtualMedia.toast.serverConnectionEstablished'),
198          );
199          connectionData.isActive = true;
200        })
201        .catch(() => {
202          this.errorToast(
203            i18n.global.t('pageVirtualMedia.toast.errorMounting'),
204          );
205          this.isActive = false;
206        })
207        .finally(() => this.endLoader());
208    },
209    stopLegacy(connectionData) {
210      this.$store
211        .dispatch('virtualMedia/unmountImage', connectionData.id)
212        .then(() => {
213          this.successToast(
214            i18n.global.t('pageVirtualMedia.toast.serverClosedSuccessfully'),
215          );
216          connectionData.isActive = false;
217        })
218        .catch(() =>
219          this.errorToast(
220            i18n.global.t('pageVirtualMedia.toast.errorUnmounting'),
221          ),
222        )
223        .finally(() => this.endLoader());
224    },
225    saveConnection(connectionData) {
226      this.modalConfigureConnection.serverUri = connectionData.serverUri;
227      this.modalConfigureConnection.username = connectionData.username;
228      this.modalConfigureConnection.password = connectionData.password;
229      this.modalConfigureConnection.isRW = connectionData.isRW;
230    },
231    configureConnection(connectionData) {
232      this.modalConfigureConnection = connectionData;
233      this.showConfigureConnectionModal = true;
234    },
235    concatId(val) {
236      return val.split(' ').join('_').toLowerCase();
237    },
238  },
239};
240</script>
241