ui-modules/utils/server-status/server-status.js (160 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import './server-status.less'; import angular from 'angular'; import uibModal from 'angular-ui-bootstrap/src/modal/index-nocss'; import modalTemplate from './server-status.template.html'; import {setSensitiveFields} from "../sensitive-field/sensitive-field"; const MODULE_NAME = 'br.utils.server-status'; const COOKIE_KEY = "br-server-status"; const COOKIE_EXPIRY = 15 * 60000; const REFRESH_INTERVAL = 15000; const DEFAULT_COOKIE = {dismissed: false}; angular.module(MODULE_NAME, [uibModal]) .directive('brServerStatus', BrServerStatusDirective); export default MODULE_NAME; const LOGIN_PAGE_HEADER = "X_BROOKLYN_LOGIN_PAGE"; export function BrServerStatusDirective() { return { restrict: 'A', controller: ['$rootScope', '$scope', '$http', '$cookies', '$interval', '$uibModal', '$log', '$window', controller] }; function controller($rootScope, $scope, $http, $cookies, $interval, $uibModal, $log, $window) { let cookie = DEFAULT_COOKIE; let intervalId = $interval(checkStatus, REFRESH_INTERVAL); $scope.$on('$destroy', () => ($interval.cancel(intervalId))); let modalInstance = null; var previousState = null; function checkStatus() { cookie = $cookies.getObject(COOKIE_KEY) || DEFAULT_COOKIE; $http({method: 'GET', url: '/v1/server/up/extended'}) .then(updateState, (error) => (updateState(error, true))); } function updateState(response, error = false) { let state = BrServerStatusModalController.STATES.OK; let stateData = null; if (error) { stateData = response.data; if (stateData && stateData.SESSION_AGE_EXCEEDED) { state = BrServerStatusModalController.STATES.SESSION_AGE_EXCEEDED; } else if (stateData && stateData.SESSION_INVALIDATED) { state = BrServerStatusModalController.STATES.SESSION_INVALIDATED; }else if(response.status === 404) { state = BrServerStatusModalController.STATES.NO_CONNECTION; }else if(response.status === 401 || response.status === 403 ) { if( response.headers(LOGIN_PAGE_HEADER)) { $window.location.href = '/' + response.headers(LOGIN_PAGE_HEADER); } state = BrServerStatusModalController.STATES.USER_NOT_AUTHORIZED; }else { if (previousState === null || previousState == BrServerStatusModalController.STATES.OK){ state = BrServerStatusModalController.STATES.OTHER_ERROR; } else { // we're now getting a new server error, possibly because the old error has expired // but changing the message for the user would be confusing so don't do that! // eg we get a 405 after a 307 (which the browser handles automatically) if redirected to Google for login $log.info("Server responded \"" + stateData + "\" after previous problem \"" + previousState + "\""); // no update state = previousState; } } stateData = response; } else { stateData = response.data; if (stateData.shuttingDown) { state = BrServerStatusModalController.STATES.STOPPING; } else if (!stateData.up) { state = BrServerStatusModalController.STATES.STARTING; } else if (stateData.healthy && stateData.ha.planeId && stateData.ha.masterId !== stateData.ha.ownId) { state = BrServerStatusModalController.STATES.NOT_HA_MASTER; } else if (!stateData.healthy) { state = BrServerStatusModalController.STATES.UNHEALTHY; } let sensitiveFields = stateData['brooklyn.security.sensitive.fields']; if (sensitiveFields) { setSensitiveFields(sensitiveFields.tokens, sensitiveFields['plaintext.blocked']); } } previousState = state; $rootScope.$broadcast('br-server-state-update', {state: state, stateData: stateData}); if (state !== BrServerStatusModalController.STATES.OK && !cookie.dismissed && cookie.dismissedSate !== state) { openModal(state, stateData); } } function openModal(state, stateData) { if (!modalInstance) { modalInstance = $uibModal.open({ animation: true, template: modalTemplate, backdropClass: 'server-status-index', windowClass: 'server-status-index', controller: BrServerStatusModalController, controllerAs: 'vm', size: 'md', resolve: { state: () => (state), stateData: () => (stateData) } }); modalInstance.result.then((reason) => { if (reason === 'understood') { cookie.dismissed = true; cookie.dismissedSate = state; $cookies.putObject(COOKIE_KEY, cookie, {expires: getCookieExpiryDate()}); } }, () => (modalInstance = null)); } } function getCookieExpiryDate() { return new Date(Date.now() + COOKIE_EXPIRY); } checkStatus(); class BrServerStatusModalController { static STATES = { OK: 'OK', STARTING: 'STARTING', STOPPING: 'STOPPING', NOT_HA_MASTER: 'NOT-HA-MASTER', NO_CONNECTION: 'NO-CONNECTION', UNHEALTHY: 'UNHEALTHY', SESSION_INVALIDATED: 'SESSION_INVALIDATED', SESSION_AGE_EXCEEDED: 'SESSION_AGE_EXCEEDED', OTHER_ERROR: 'OTHER_ERROR', USER_NOT_AUTHORIZED: 'USER_NOT_AUTHORIZED' }; static $inject = ['$scope', '$uibModalInstance', 'state', 'stateData']; constructor($scope, $uibModalInstance, state, stateData) { this.$uibModalInstance = $uibModalInstance; this.state = state; this.stateData = stateData; $scope.$on('br-server-state-update', (event, value) => { this.state = value.state; this.stateData = value.stateData; }); } close(reason = 'understood') { this.$uibModalInstance.close(reason); } get masterUri() { if (this.stateData.ha.nodes.hasOwnProperty(this.stateData.ha.masterId)) { return this.stateData.ha.nodes[this.stateData.ha.masterId].nodeUri; } else { return null; } } get nodes() { let currentNodeId = this.stateData.ha.ownId; let masterNode = null; let result = []; for (let nodeId in this.stateData.ha.nodes) { let currentNode = this.stateData.ha.nodes[nodeId]; if (currentNode.nodeId === this.stateData.ha.masterId) { masterNode = currentNode; } result.push(currentNode); } return result.reduce((pre, node) => { node.state = ((node.localTimestamp + 30 * 1000) < masterNode.localTimestamp) ? 'offline' : 'online'; node.isMasterNode = node.nodeId === masterNode.nodeId; node.isCurrentNode = node.nodeId === currentNodeId; pre.push(node); return pre; }, []); } } } }