Add code for Serial Over LAN

- The output of serial connection of the hosts on the workstation
terminal.
- The library used is xterm which will provide the terminal to show the
data.

Signed-off-by: Sukanya Pandey <sukapan1@in.ibm.com>
Change-Id: I6000cae42f237fffe216e2079cf2a6c39db236fd
diff --git a/package-lock.json b/package-lock.json
index 933f86c..f99d516 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18595,6 +18595,21 @@
       "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
       "dev": true
     },
+    "xterm": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/xterm/-/xterm-4.6.0.tgz",
+      "integrity": "sha512-98211RIDrAECqpsxs6gbilwMcxLtxSDIvtzZUIqP1xIByXtuccJ4pmMhHGJATZeEGe/reARPMqwPINK8T7jGZg=="
+    },
+    "xterm-addon-attach": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/xterm-addon-attach/-/xterm-addon-attach-0.6.0.tgz",
+      "integrity": "sha512-Mo8r3HTjI/EZfczVCwRU6jh438B4WLXxdFO86OB7bx0jGhwh2GdF4ifx/rP+OB+Cb2vmLhhVIZ00/7x3YSP3dg=="
+    },
+    "xterm-addon-fit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.4.0.tgz",
+      "integrity": "sha512-p4BESuV/g2L6pZzFHpeNLLnep9mp/DkF3qrPglMiucSFtD8iJxtMufEoEJbN8LZwB4i+8PFpFvVuFrGOSpW05w=="
+    },
     "y18n": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
diff --git a/package.json b/package.json
index 5482f54..8c90675 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,10 @@
     "vue-i18n": "8.15.3",
     "vue-router": "3.1.3",
     "vuelidate": "0.7.5",
-    "vuex": "3.0.1"
+    "vuex": "3.0.1",
+    "xterm": "4.6.0",
+    "xterm-addon-attach": "0.6.0",
+    "xterm-addon-fit": "0.4.0"
   },
   "devDependencies": {
     "@kazupon/vue-i18n-loader": "0.3.0",
diff --git a/src/components/AppNavigation/AppNavigation.vue b/src/components/AppNavigation/AppNavigation.vue
index 9c5295a..1dfba11 100644
--- a/src/components/AppNavigation/AppNavigation.vue
+++ b/src/components/AppNavigation/AppNavigation.vue
@@ -40,6 +40,9 @@
               <b-nav-item to="/control/reboot-bmc">
                 {{ $t('appNavigation.rebootBmc') }}
               </b-nav-item>
+              <b-nav-item to="/control/serial-over-lan">
+                {{ $t('appNavigation.serialOverLan') }}
+              </b-nav-item>
               <b-nav-item to="/control/server-led">
                 {{ $t('appNavigation.serverLed') }}
               </b-nav-item>
diff --git a/src/layouts/ConsoleLayout.vue b/src/layouts/ConsoleLayout.vue
new file mode 100644
index 0000000..99f8d9f
--- /dev/null
+++ b/src/layouts/ConsoleLayout.vue
@@ -0,0 +1,9 @@
+<template>
+  <router-view />
+</template>
+
+<script>
+export default {
+  name: 'Console'
+};
+</script>
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index f239058..f0494c7 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -85,6 +85,7 @@
     "primaryNavigation": "Primary navigation",
     "rebootBmc": "@:appPageTitle.rebootBmc",
     "sensors": "@:appPageTitle.sensors",
+    "serialOverLan": "@:appPageTitle.serialOverLan",
     "serverLed": "@:appPageTitle.serverLed",
     "serverPowerOperations": "@:appPageTitle.serverPowerOperations",
     "snmpSettings": "@:appPageTitle.snmpSettings",
@@ -103,6 +104,7 @@
     "profileSettings":"Profile settings",
     "rebootBmc": "Reboot BMC",
     "sensors": "Sensors",
+    "serialOverLan": "Serial over LAN console",
     "serverLed": "Server LED",
     "serverPowerOperations": "Server power operations",
     "snmpSettings": "SNMP settings",
@@ -388,6 +390,11 @@
       "upperCritical": "Upper critical"
     }
   },
+  "pageSerialoverLAN": {
+    "openNewTab": "Open in new tab",
+    "subTitle": "Access the Serial over LAN console",
+    "subTitleDesc": "The Serial over LAN (SoL) console redirects the output of the server's serial port to a browser window on your workstation."
+  },
   "pageServerLed": {
     "serverLedSubTitle": "Server indicator LED",
     "serverLedTitle": "LED light control",
diff --git a/src/router/index.js b/src/router/index.js
index 73f3186..a3d2806 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -3,6 +3,7 @@
 import store from '../store/index';
 import AppLayout from '../layouts/AppLayout.vue';
 import LoginLayout from '@/layouts/LoginLayout';
+import ConsoleLayout from '@/layouts/ConsoleLayout.vue';
 
 Vue.use(VueRouter);
 
@@ -113,6 +114,14 @@
         }
       },
       {
+        path: '/control/serial-over-lan',
+        name: 'serial-over-lan',
+        component: () => import('@/views/Control/SerialOverLan'),
+        meta: {
+          title: 'appPageTitle.serialOverLan'
+        }
+      },
+      {
         path: '/control/server-power-operations',
         name: 'server-power-operations',
         component: () => import('@/views/Control/ServerPowerOperations'),
@@ -143,6 +152,24 @@
         }
       }
     ]
+  },
+  {
+    path: '/console',
+    component: ConsoleLayout,
+    meta: {
+      requiresAuth: true
+    },
+    children: [
+      {
+        path: '/console/serial-over-lan-console',
+        name: 'serial-over-lan',
+        component: () =>
+          import('@/views/Control/SerialOverLan/SerialOverLanConsole'),
+        meta: {
+          title: 'appPageTitle.serialOverLan'
+        }
+      }
+    ]
   }
 ];
 
diff --git a/src/views/Control/SerialOverLan/SerialOverLan.vue b/src/views/Control/SerialOverLan/SerialOverLan.vue
new file mode 100644
index 0000000..61f91e0
--- /dev/null
+++ b/src/views/Control/SerialOverLan/SerialOverLan.vue
@@ -0,0 +1,55 @@
+<template>
+  <b-container fluid="xl">
+    <page-title />
+
+    <page-section :section-title="$t('pageSerialoverLAN.subTitle')">
+      <p>{{ $t('pageSerialoverLAN.subTitleDesc') }}</p>
+
+      <div class="terminal-container">
+        <serial-over-lan-console />
+      </div>
+      <div class="text-right">
+        <b-button
+          variant="link"
+          type="button"
+          class="button-launch"
+          @click="openConsoleWindow()"
+        >
+          <icon-launch />
+
+          {{ $t('pageSerialoverLAN.openNewTab') }}
+        </b-button>
+      </div>
+    </page-section>
+  </b-container>
+</template>
+
+<script>
+import IconLaunch from '@carbon/icons-vue/es/launch/32';
+import PageTitle from '@/components/Global/PageTitle';
+import PageSection from '@/components/Global/PageSection';
+import SerialOverLanConsole from './SerialOverLanConsole';
+
+export default {
+  name: 'SerialOverLan',
+  components: { IconLaunch, PageSection, PageTitle, SerialOverLanConsole },
+  methods: {
+    openConsoleWindow() {
+      window.open(
+        '#/console/serial-over-lan-console',
+        '_blank',
+        'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=600,height=550'
+      );
+    }
+  }
+};
+</script>
+
+<style scoped>
+.button-launch > svg {
+  height: 25px;
+}
+.terminal-container {
+  width: 100%;
+}
+</style>
diff --git a/src/views/Control/SerialOverLan/SerialOverLanConsole.vue b/src/views/Control/SerialOverLan/SerialOverLanConsole.vue
new file mode 100644
index 0000000..69ccf8d
--- /dev/null
+++ b/src/views/Control/SerialOverLan/SerialOverLanConsole.vue
@@ -0,0 +1,74 @@
+<template>
+  <div id="terminal" ref="panel"></div>
+</template>
+
+<script>
+import { AttachAddon } from 'xterm-addon-attach';
+import { FitAddon } from 'xterm-addon-fit';
+import { Terminal } from 'xterm';
+
+export default {
+  name: 'SerialOverLanConsole',
+  mounted() {
+    this.openTerminal();
+  },
+  methods: {
+    openTerminal() {
+      const token = this.$store.getters['authentication/token'];
+
+      const ws = new WebSocket(`wss://${window.location.host}/console0`, [
+        token
+      ]);
+
+      // Refer https://github.com/xtermjs/xterm.js/ for xterm implementation and addons.
+
+      const term = new Terminal({
+        fontSize: 15,
+        fontFamily:
+          'SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace'
+      });
+
+      const attachAddon = new AttachAddon(ws);
+      term.loadAddon(attachAddon);
+
+      const fitAddon = new FitAddon();
+      term.loadAddon(fitAddon);
+
+      const SOL_THEME = {
+        background: '#19273c',
+        cursor: 'rgba(83, 146, 255, .5)',
+        scrollbar: 'rgba(83, 146, 255, .5)'
+      };
+      term.setOption('theme', SOL_THEME);
+
+      term.open(this.$refs.panel);
+      fitAddon.fit();
+
+      try {
+        ws.onopen = function() {
+          console.log('websocket console0/ opened');
+        };
+        ws.onclose = function(event) {
+          console.log(
+            'websocket console0/ closed. code: ' +
+              event.code +
+              ' reason: ' +
+              event.reason
+          );
+        };
+      } catch (error) {
+        console.log(error);
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+@import '~xterm/css/xterm.css';
+
+#terminal {
+  height: 25em;
+  overflow: hidden;
+}
+</style>
diff --git a/src/views/Control/SerialOverLan/index.js b/src/views/Control/SerialOverLan/index.js
new file mode 100644
index 0000000..7c8bc7c
--- /dev/null
+++ b/src/views/Control/SerialOverLan/index.js
@@ -0,0 +1,2 @@
+import SerialOverLan from './SerialOverLan.vue';
+export default SerialOverLan;