summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoshie Muranaka <yoshiemuranaka@gmail.com>2019-05-24 14:33:56 -0500
committerGunnar Mills <gmills@us.ibm.com>2019-06-21 14:29:40 +0000
commite4194ce0dc8a941c4f30fd0995f9ba4c13cec560 (patch)
tree15887d0e4061b7dec40991f2f2fb8a590d9835af
parente4ae854c217344b4f35717e922083a253f43bfa0 (diff)
downloadphosphor-webui-e4194ce0dc8a941c4f30fd0995f9ba4c13cec560.tar.gz
phosphor-webui-e4194ce0dc8a941c4f30fd0995f9ba4c13cec560.zip
Add remote logging server
Remote logging enables the user to configure a remote server to stream out local logs. This feature will be available on the Event Log page. The user can add a remote server, edit/change an existing server configuration and remove/disable the remote server. Resolves openbmc/phosphor-webui#68 Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com> Change-Id: I8284cbdbdaaf85f5c95f237efc72290c66904b40
-rw-r--r--app/common/services/api-utils.js59
-rw-r--r--app/common/styles/base/forms.scss11
-rw-r--r--app/common/styles/base/icons.scss15
-rw-r--r--app/common/styles/elements/modals.scss25
-rw-r--r--app/index.js3
-rw-r--r--app/overview/controllers/system-overview-controller.html2
-rw-r--r--app/server-health/controllers/log-controller.html7
-rw-r--r--app/server-health/directives/remote-logging-server-modal.html42
-rw-r--r--app/server-health/directives/remote-logging-server.html21
-rw-r--r--app/server-health/directives/remote-logging-server.js157
-rw-r--r--app/server-health/styles/log.scss28
11 files changed, 366 insertions, 4 deletions
diff --git a/app/common/services/api-utils.js b/app/common/services/api-utils.js
index 6e46c9c..e796f43 100644
--- a/app/common/services/api-utils.js
+++ b/app/common/services/api-utils.js
@@ -1557,6 +1557,65 @@ window.angular && (function(angular) {
});
return $q.all(promises);
},
+ setRemoteLoggingServer: (data) => {
+ const ip = data.hostname;
+ const port = data.port;
+ const setIPRequest = $http({
+ method: 'PUT',
+ url: DataService.getHost() +
+ '/xyz/openbmc_project/logging/config/remote/attr/Address',
+ withCredentials: true,
+ data: {'data': ip}
+ });
+ const setPortRequest = $http({
+ method: 'PUT',
+ url: DataService.getHost() +
+ '/xyz/openbmc_project/logging/config/remote/attr/Port',
+ withCredentials: true,
+ data: {'data': port}
+ });
+ const promises = [setIPRequest, setPortRequest];
+ return $q.all(promises);
+ },
+ getRemoteLoggingServer: () => {
+ return $http({
+ method: 'GET',
+ url: DataService.getHost() +
+ '/xyz/openbmc_project/logging/config/remote',
+ withCredentials: true
+ })
+ .then((response) => {
+ const remoteServer = response.data.data;
+ if (remoteServer === undefined) {
+ return undefined;
+ }
+ const hostname = remoteServer.Address;
+ const port = remoteServer.Port;
+ if (hostname === '') {
+ return undefined;
+ } else {
+ return {
+ hostname, port
+ }
+ }
+ });
+ },
+ disableRemoteLoggingServer: () => {
+ return SERVICE.setRemoteLoggingServer({hostname: '', port: 0});
+ },
+ updateRemoteLoggingServer: (data) => {
+ // Recommended to disable existing configuration
+ // before updating config to new server
+ // https://github.com/openbmc/phosphor-logging#changing-the-rsyslog-server
+ return SERVICE.disableRemoteLoggingServer()
+ .then(() => {
+ return SERVICE.setRemoteLoggingServer(data);
+ })
+ .catch(() => {
+ // try updating server even if initial disable attempt fails
+ return SERVICE.setRemoteLoggingServer(data);
+ });
+ },
getPowerConsumption: function() {
return $http({
method: 'GET',
diff --git a/app/common/styles/base/forms.scss b/app/common/styles/base/forms.scss
index 21253e7..5e75bcc 100644
--- a/app/common/styles/base/forms.scss
+++ b/app/common/styles/base/forms.scss
@@ -10,6 +10,13 @@ label, legend {
}
}
+.label__helper-text {
+ color: $darkgrey;
+ line-height: 1.2;
+ font-size: 0.9em;
+ margin-bottom: 0.4em;
+}
+
input[type='email'],
input[type='number'],
input[type='password'],
@@ -113,3 +120,7 @@ select{
max-height: none;
}
}
+.form__validation-message {
+ color: $error-color;
+ font-size: 0.9em;
+}
diff --git a/app/common/styles/base/icons.scss b/app/common/styles/base/icons.scss
index 43d3669..557c857 100644
--- a/app/common/styles/base/icons.scss
+++ b/app/common/styles/base/icons.scss
@@ -126,3 +126,18 @@
@extend .icon__up-arrow;
transform: rotate(180deg);
}
+
+.icon__edit {
+ @include status-icon;
+ background-image: url(../assets/images/icon-edit-blue.svg);
+}
+
+.icon__delete {
+ @include status-icon;
+ background-image: url(../assets/images/icon-trashcan-blue.svg);
+}
+
+.icon__close {
+ @include status-icon;
+ background-image: url(../assets/images/crit-x-black.svg);
+}
diff --git a/app/common/styles/elements/modals.scss b/app/common/styles/elements/modals.scss
index 1a8b71f..0bb81d5 100644
--- a/app/common/styles/elements/modals.scss
+++ b/app/common/styles/elements/modals.scss
@@ -18,7 +18,7 @@
@include fastTransition-all;
}
-.modal {
+.modal:not(.uib-modal) {
width: auto;
height: auto;
left: 50%;
@@ -79,3 +79,26 @@
}
}
}
+
+.uib-modal.fade.in {
+ opacity: 1;
+}
+.uib-modal.in .modal-dialog {
+ transform: translate(0, 10vh);
+ margin-top: 50px;
+ .icon__close {
+ margin: 0;
+ padding: 0;
+ }
+ .modal-content {
+ border-radius: 0;
+ border-color: $black;
+ }
+}
+
+.modal-backdrop.in {
+ opacity: 0.5;
+}
+.uib-modal__content {
+ padding: 1em;
+}
diff --git a/app/index.js b/app/index.js
index 6303142..1d54b45 100644
--- a/app/index.js
+++ b/app/index.js
@@ -22,7 +22,6 @@ import ngToast from 'ng-toast';
import ngToast_animate from 'ng-toast/dist/ngToast-animations.css';
import ngToast_style from 'ng-toast/dist/ngToast.css';
-
require('./styles/index.scss');
var config = require('../config.json');
@@ -77,6 +76,7 @@ import log_controller from './server-health/controllers/log-controller.js';
import sensors_overview_controller from './server-health/controllers/sensors-overview-controller.js';
import syslog_controller from './server-health/controllers/syslog-controller.js';
import syslog_filter from './common/directives/syslog-filter.js';
+import remote_logging_server from './server-health/directives/remote-logging-server.js';
import redfish_index from './redfish/index.js';
import redfish_controller from './redfish/controllers/redfish-controller.js';
@@ -100,6 +100,7 @@ window.angular && (function(angular) {
// Dependencies
'ngRoute', 'angular-clipboard', 'ngToast', 'ngAnimate',
'ngMessages', 'app.common.directives.dirPagination', 'ngSanitize',
+ 'ui.bootstrap',
// Basic resources
'app.common.services', 'app.common.directives',
'app.common.filters',
diff --git a/app/overview/controllers/system-overview-controller.html b/app/overview/controllers/system-overview-controller.html
index 31e2917..0403a85 100644
--- a/app/overview/controllers/system-overview-controller.html
+++ b/app/overview/controllers/system-overview-controller.html
@@ -204,7 +204,7 @@
<form name="edit_hostname_text">
<label for="editServerName">Hostname</label>
- <p>Hostname must be less than 64 characters and must not contain spaces.</p>
+ <p class="label__helper-text">Hostname must be less than 64 characters and must not contain spaces.</p>
<input id="editServerName" class="modal__edit-server-name" type="text" ng-model="newHostname" ng-trim="false"
name="hostname" ng-pattern="/^\S{0,64}$/" required autofocus />
<span class="modal__error" ng-show="edit_hostname_text.hostname.$error.pattern">Invalid format.
diff --git a/app/server-health/controllers/log-controller.html b/app/server-health/controllers/log-controller.html
index 0a985c5..34a2ec3 100644
--- a/app/server-health/controllers/log-controller.html
+++ b/app/server-health/controllers/log-controller.html
@@ -1,7 +1,12 @@
<loader loading="loading"></loader>
<div id="event-log">
<div class="row column">
- <h1>Event log</h1>
+ <div class="column small-6 large-7 no-padding">
+ <h1>Event log</h1>
+ </div>
+ <div class="column small-6 large-5">
+ <remote-logging-server class="remote-logging-server"></remote-logging-server>
+ </div>
</div>
<section class="row column">
<div class="page-header">
diff --git a/app/server-health/directives/remote-logging-server-modal.html b/app/server-health/directives/remote-logging-server-modal.html
new file mode 100644
index 0000000..eba57af
--- /dev/null
+++ b/app/server-health/directives/remote-logging-server-modal.html
@@ -0,0 +1,42 @@
+<div role="dialog" class="uib-modal__content remote-logging-server__modal">
+ <button type="button" class="icon icon__close float-right" ng-click="$close()"></button>
+ <div class="modal-header">
+ <h2 class="modal-title" id="dialog_label">{{activeModalProps.title}}</h2>
+ </div>
+ <form name="form">
+ <div ng-if="activeModal !== 2" class="modal-body">
+ <label for="remoteServerIP">Hostname or IP Address</label>
+ <input id="remoteServerIP" type="text" required name="hostname"
+ ng-model="remoteServerForm.hostname" />
+ <div ng-if="form.hostname.$invalid && form.hostname.$dirty"
+ class="form__validation-message">
+ <span ng-show="form.hostname.$error.required">Field is required</span>
+ </div>
+ <label for="remoteServerPort">Port</label>
+ <p class="label__helper-text">Value must be between 0 – 65535</p>
+ <input id="remoteServerPort" type="number" required name="port"
+ min="0" max="65535" ng-model="remoteServerForm.port"/>
+ <div ng-if="form.port.$invalid && form.port.$dirty"
+ class="form__validation-message">
+ <span ng-show="form.port.$error.required">Field is required</span>
+ <span ng-show="form.port.$error.min || form.port.$error.max">
+ Value must be between 0 – 65535
+ </span>
+ </div>
+ </div>
+ <div ng-if="activeModal === 2" class="modal-body">
+ <p>Are you sure you want to remove remote logging server
+ {{remoteServer.hostname}}?</p>
+ </div>
+ <div class="modal-footer">
+ <button class="button btn-secondary" ng-click="$close()" type="button">
+ Cancel
+ </button>
+ <button class="button btn-primary" type="submit"
+ ng-click="$close(activeModal)" ng-disabled="form.$invalid"
+ ng-class="{'disabled': form.$invalid}">
+ {{activeModalProps.actionLabel}}
+ </button>
+ </div>
+ </form>
+</div>
diff --git a/app/server-health/directives/remote-logging-server.html b/app/server-health/directives/remote-logging-server.html
new file mode 100644
index 0000000..28fc313
--- /dev/null
+++ b/app/server-health/directives/remote-logging-server.html
@@ -0,0 +1,21 @@
+<p class="content-label">Remote Logging Server</p>
+<div ng-if="!loadError && !remoteServer">
+ <button ng-click="initModal(0)" class="modal__trigger">
+ <span class="icon icon__plus"></span>
+ Add server
+ </button>
+</div>
+<div ng-if="!loadError && remoteServer">
+ <p class="inline remote-logging-server__details">
+ {{remoteServer.hostname}}
+ </p>
+ <button ng-click="initModal(1)" class="modal__trigger">
+ <span class="icon icon__edit"></span>
+ </button>
+ <button ng-click="initModal(2)" class="modal__trigger">
+ <span class="icon icon__delete"></span>
+ </button>
+</div>
+<div class="text-right" ng-if="loadError">
+ <p>--</p>
+</div>
diff --git a/app/server-health/directives/remote-logging-server.js b/app/server-health/directives/remote-logging-server.js
new file mode 100644
index 0000000..4e8ad6f
--- /dev/null
+++ b/app/server-health/directives/remote-logging-server.js
@@ -0,0 +1,157 @@
+window.angular && (function(angular) {
+ 'use strict';
+
+ angular.module('app.common.directives').directive('remoteLoggingServer', [
+ 'APIUtils',
+ function(APIUtils) {
+ return {
+ 'restrict': 'E', 'template': require('./remote-logging-server.html'),
+ 'controller': [
+ '$scope', '$uibModal', 'toastService',
+ function($scope, $uibModal, toastService) {
+ const modalActions = {
+ ADD: 0,
+ EDIT: 1,
+ REMOVE: 2,
+ properties: {
+ 0: {
+ title: 'Add remote logging server',
+ actionLabel: 'Add',
+ successMessage: 'Connected to remote logging server.',
+ errorMessage: 'Unable to connect to server.'
+ },
+ 1: {
+ title: 'Edit remote logging server',
+ actionLabel: 'Save',
+ successMessage: 'Connected to remote logging server.',
+ errorMessage: 'Unable to save remote logging server.'
+ },
+ 2: {
+ title: 'Remove remote logging server',
+ actionLabel: 'Remove',
+ successMessage: 'Remote logging server removed.',
+ errorMessage: 'Unable to remove remote logging server.'
+ }
+ }
+ };
+
+ const modalTemplate =
+ require('./remote-logging-server-modal.html');
+
+ $scope.activeModal;
+ $scope.activeModalProps;
+
+ $scope.remoteServer;
+ $scope.remoteServerForm;
+ $scope.loadError = true;
+
+ $scope.initModal = (type) => {
+ if (type === undefined) {
+ return;
+ }
+ $scope.activeModal = type;
+ $scope.activeModalProps = modalActions.properties[type];
+
+ $uibModal
+ .open({
+ template: modalTemplate,
+ windowTopClass: 'uib-modal',
+ scope: $scope,
+ ariaLabelledBy: 'dialog_label'
+ })
+ .result
+ .then((action) => {
+ switch (action) {
+ case modalActions.ADD:
+ addServer();
+ break;
+ case modalActions.EDIT:
+ editServer();
+ break;
+ case modalActions.REMOVE:
+ removeServer();
+ break;
+ default:
+ setFormValues();
+ }
+ })
+ .catch(() => {
+ // reset form when modal overlay clicked
+ // and modal closes
+ setFormValues();
+ })
+ };
+
+ const addServer = () => {
+ $scope.loading = true;
+ APIUtils.setRemoteLoggingServer($scope.remoteServerForm)
+ .then(() => {
+ $scope.loading = false;
+ $scope.remoteServer = {...$scope.remoteServerForm};
+ toastService.success(
+ $scope.activeModalProps.successMessage);
+ })
+ .catch(() => {
+ $scope.loading = false;
+ $scope.remoteServer = undefined;
+ setFormValues();
+ toastService.error(
+ $scope.activeModalProps.errorMessage);
+ })
+ };
+
+ const editServer = () => {
+ $scope.loading = true;
+ APIUtils.updateRemoteLoggingServer($scope.remoteServerForm)
+ .then(() => {
+ $scope.loading = false;
+ $scope.remoteServer = {...$scope.remoteServerForm};
+ toastService.success(
+ $scope.activeModalProps.successMessage);
+ })
+ .catch(() => {
+ $scope.loading = false;
+ setFormValues();
+ toastService.error(
+ $scope.activeModalProps.errorMessage);
+ })
+ };
+
+ const removeServer = () => {
+ $scope.loading = true;
+ APIUtils.disableRemoteLoggingServer()
+ .then(() => {
+ $scope.loading = false;
+ $scope.remoteServer = undefined;
+ setFormValues();
+ toastService.success(
+ $scope.activeModalProps.successMessage);
+ })
+ .catch(() => {
+ $scope.loading = false;
+ toastService.error(
+ $scope.activeModalProps.errorMessage);
+ })
+ };
+
+ const setFormValues = () => {
+ $scope.remoteServerForm = {...$scope.remoteServer};
+ };
+
+ this.$onInit = () => {
+ APIUtils.getRemoteLoggingServer()
+ .then((remoteServer) => {
+ $scope.loadError = false;
+ $scope.remoteServer = remoteServer;
+ setFormValues();
+ })
+ .catch(() => {
+ $scope.loadError = true;
+ })
+ };
+ }
+ ]
+ }
+ }
+ ])
+})(window.angular); \ No newline at end of file
diff --git a/app/server-health/styles/log.scss b/app/server-health/styles/log.scss
index cc58a60..675dc26 100644
--- a/app/server-health/styles/log.scss
+++ b/app/server-health/styles/log.scss
@@ -370,6 +370,34 @@
word-break: break-word;
}
+.remote-logging-server {
+ float: right;
+ .modal__trigger {
+ padding: 0;
+ color: $primebtn__bg;
+ .icon {
+ margin: 0;
+ width: 20px;
+ height: 20px;
+ vertical-align: text-bottom;
+ }
+ }
+}
+
+.remote-logging-server__details {
+ margin-right: 0.4em;
+}
+
+.remote-logging-server__modal {
+ input {
+ margin-bottom: 30px;
+ max-width: 70%;
+ + .form__validation-message {
+ position: absolute;
+ margin-top: -30px;
+ }
+ }
+}
//end event-log__events
OpenPOWER on IntegriCloud