xref: /openbmc/webui-vue/src/views/Operations/VirtualMedia/VirtualMedia.vue (revision ce7db82c9582c4dac04ac81d9af6b557ae7965e3)
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-right"
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-right"
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      :connection="modalConfigureConnection"
94      @ok="saveConnection"
95    />
96  </b-container>
97</template>
98
99<script>
100import PageTitle from '@/components/Global/PageTitle';
101import PageSection from '@/components/Global/PageSection';
102import BVToastMixin from '@/components/Mixins/BVToastMixin';
103import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
104import ModalConfigureConnection from './ModalConfigureConnection';
105import NbdServer from '@/utilities/NBDServer';
106import FormFile from '@/components/Global/FormFile';
107import { useI18n } from 'vue-i18n';
108import i18n from '@/i18n';
109
110export default {
111  name: 'VirtualMedia',
112  components: { PageTitle, PageSection, ModalConfigureConnection, FormFile },
113  mixins: [BVToastMixin, LoadingBarMixin],
114  data() {
115    return {
116      $t: useI18n().t,
117      modalConfigureConnection: null,
118      loadImageFromExternalServer:
119        process.env.VUE_APP_VIRTUAL_MEDIA_LIST_ENABLED === 'true'
120          ? true
121          : false,
122    };
123  },
124  computed: {
125    proxyDevices() {
126      return this.$store.getters['virtualMedia/proxyDevices'];
127    },
128    legacyDevices() {
129      return this.$store.getters['virtualMedia/legacyDevices'];
130    },
131  },
132  created() {
133    this.$store.dispatch('global/getSystemInfo');
134    if (this.proxyDevices.length > 0 || this.legacyDevices.length > 0) return;
135    this.startLoader();
136    this.$store
137      .dispatch('virtualMedia/getData')
138      .finally(() => this.endLoader());
139  },
140  methods: {
141    startVM(device) {
142      const token = this.$store.getters['authentication/token'];
143      device.nbd = new NbdServer(
144        `wss://${window.location.host}${device.websocket}`,
145        device.file,
146        device.id,
147        token,
148      );
149      device.nbd.socketStarted = () =>
150        this.successToast(
151          i18n.global.t('pageVirtualMedia.toast.serverRunning'),
152        );
153      device.nbd.errorReadingFile = () =>
154        this.errorToast(
155          i18n.global.t('pageVirtualMedia.toast.errorReadingFile'),
156        );
157      device.nbd.socketClosed = (code) => {
158        if (code === 1000)
159          this.successToast(
160            i18n.global.t('pageVirtualMedia.toast.serverClosedSuccessfully'),
161          );
162        else
163          this.errorToast(
164            i18n.global.t('pageVirtualMedia.toast.serverClosedWithErrors'),
165          );
166        device.file = null;
167        device.isActive = false;
168      };
169
170      device.nbd.start();
171      device.isActive = true;
172    },
173    stopVM(device) {
174      device.nbd.stop();
175    },
176    startLegacy(connectionData) {
177      var data = {};
178      data.Image = connectionData.serverUri;
179      data.UserName = connectionData.username;
180      data.Password = connectionData.password;
181      data.WriteProtected = !connectionData.isRW;
182      this.startLoader();
183      this.$store
184        .dispatch('virtualMedia/mountImage', {
185          id: connectionData.id,
186          data: data,
187        })
188        .then(() => {
189          this.successToast(
190            i18n.global.t('pageVirtualMedia.toast.serverConnectionEstablished'),
191          );
192          connectionData.isActive = true;
193        })
194        .catch(() => {
195          this.errorToast(
196            i18n.global.t('pageVirtualMedia.toast.errorMounting'),
197          );
198          this.isActive = false;
199        })
200        .finally(() => this.endLoader());
201    },
202    stopLegacy(connectionData) {
203      this.$store
204        .dispatch('virtualMedia/unmountImage', connectionData.id)
205        .then(() => {
206          this.successToast(
207            i18n.global.t('pageVirtualMedia.toast.serverClosedSuccessfully'),
208          );
209          connectionData.isActive = false;
210        })
211        .catch(() =>
212          this.errorToast(
213            i18n.global.t('pageVirtualMedia.toast.errorUnmounting'),
214          ),
215        )
216        .finally(() => this.endLoader());
217    },
218    saveConnection(connectionData) {
219      this.modalConfigureConnection.serverUri = connectionData.serverUri;
220      this.modalConfigureConnection.username = connectionData.username;
221      this.modalConfigureConnection.password = connectionData.password;
222      this.modalConfigureConnection.isRW = connectionData.isRW;
223    },
224    configureConnection(connectionData) {
225      this.modalConfigureConnection = connectionData;
226      this.$bvModal.show('configure-connection');
227    },
228    concatId(val) {
229      return val.split(' ').join('_').toLowerCase();
230    },
231  },
232};
233</script>
234