You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by am...@apache.org on 2020/02/13 23:44:40 UTC
[atlas] branch master updated: ATLAS-3604: Data Migration status
display.
This is an automated email from the ASF dual-hosted git repository.
amestry pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git
The following commit(s) were added to refs/heads/master by this push:
new 015577e ATLAS-3604: Data Migration status display.
015577e is described below
commit 015577ecf4976a4b15e0e86d57b786cd21b2e86b
Author: Nikhil Bonte <ni...@freestoneinfotech.com>
AuthorDate: Thu Feb 13 15:34:11 2020 -0800
ATLAS-3604: Data Migration status display.
Signed-off-by: Ashutosh Mestry <am...@cloudera.com>
---
dashboardv2/gruntfile.js | 3 +-
dashboardv2/public/js/migration.js | 163 +++++++++++++++++++++
.../js/templates/migration/MigrationView_tmpl.html | 17 +++
dashboardv2/public/js/utils/Helper.js | 161 ++++++++++----------
.../public/js/views/migration/MigrationView.js | 68 +++++++++
dashboardv2/public/js/views/site/Statistics.js | 57 +++----
dashboardv2/public/migration-status.html.tpl | 80 ++++++++++
.../atlas/web/filters/ActiveServerFilter.java | 25 ++++
.../atlas/web/security/AtlasSecurityConfig.java | 1 +
9 files changed, 470 insertions(+), 105 deletions(-)
diff --git a/dashboardv2/gruntfile.js b/dashboardv2/gruntfile.js
index 174d67f..c4d5b0c 100644
--- a/dashboardv2/gruntfile.js
+++ b/dashboardv2/gruntfile.js
@@ -279,7 +279,8 @@ module.exports = function(grunt) {
}
},
files: {
- [distPath + '/index.html']: [modulesPath + 'index.html.tpl']
+ [distPath + '/index.html']: [modulesPath + 'index.html.tpl'],
+ [distPath + '/migration-status.html']: [modulesPath + 'migration-status.html.tpl']
}
}
}
diff --git a/dashboardv2/public/js/migration.js b/dashboardv2/public/js/migration.js
new file mode 100644
index 0000000..e49a69f
--- /dev/null
+++ b/dashboardv2/public/js/migration.js
@@ -0,0 +1,163 @@
+/**
+ * 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.
+ */
+
+require.config({
+ /* starting point for application */
+ 'hbs': {
+ 'disableI18n': true, // This disables the i18n helper and doesn't require the json i18n files (e.g. en_us.json)
+ 'helperPathCallback': // Callback to determine the path to look for helpers
+ function(name) { // ('/template/helpers/'+name by default)
+ return 'modules/Helpers';
+ },
+ 'templateExtension': 'html', // Set the extension automatically appended to templates
+ 'compileOptions': {} // options object which is passed to Handlebars compiler
+ },
+ 'urlArgs': "bust=" + getBustValue(),
+ /**
+ * Requested as soon as the loader has processed the configuration. It does
+ * not block any other require() calls from starting their requests for
+ * modules, it is just a way to specify some modules to load asynchronously
+ * as part of a config block.
+ * @type {Array} An array of dependencies to load.
+ */
+ 'deps': ['marionette'],
+
+ /**
+ * The number of seconds to wait before giving up on loading a script.
+ * @default 7 seconds
+ * @type {Number}
+ */
+ 'waitSeconds': 30,
+
+ 'shim': {
+ 'backbone': {
+ 'deps': ['underscore', 'jquery'],
+ 'exports': 'Backbone'
+ },
+ 'bootstrap': {
+ 'deps': ['jquery'],
+ 'exports': 'jquery'
+ },
+ 'underscore': {
+ 'exports': '_'
+ },
+ 'marionette': {
+ 'deps': ['backbone']
+ },
+ 'hbs': {
+ 'deps': ['underscore', 'handlebars']
+ },
+ 'jquery-placeholder': {
+ 'deps': ['jquery']
+ },
+ 'jquery-ui': {
+ 'deps': ['jquery']
+ },
+ 'moment-timezone': {
+ 'deps': ['moment']
+ },
+ 'moment': {
+ 'exports': ['moment']
+ },
+ 'pnotify': {
+ 'exports': ['pnotify']
+ },
+ 'jstree': {
+ 'deps': ['jquery']
+ },
+ 'd3': {
+ 'exports': ['d3']
+ }
+ },
+
+ paths: {
+ 'jquery': 'libs/jquery/js/jquery.min',
+ 'underscore': 'libs/underscore/underscore-min',
+ 'bootstrap': 'libs/bootstrap/js/bootstrap.min',
+ 'backbone': 'libs/backbone/backbone-min',
+ 'backbone.babysitter': 'libs/backbone.babysitter/lib/backbone.babysitter.min',
+ 'marionette': 'libs/backbone-marionette/backbone.marionette.min',
+ 'backbone.paginator': 'libs/backbone-paginator/backbone.paginator.min',
+ 'tmpl': 'templates',
+ 'requirejs.text': 'libs/requirejs-text/text',
+ 'handlebars': 'external_lib/require-handlebars-plugin/js/handlebars',
+ 'hbs': 'external_lib/require-handlebars-plugin/js/hbs',
+ 'i18nprecompile': 'external_lib/require-handlebars-plugin/js/i18nprecompile',
+ 'jquery-placeholder': 'libs/jquery-placeholder/js/jquery.placeholder',
+ 'platform': 'libs/platform/platform',
+ 'pnotify': 'external_lib/pnotify/pnotify.custom.min',
+ 'pnotify.buttons': 'external_lib/pnotify/pnotify.custom.min',
+ 'pnotify.confirm': 'external_lib/pnotify/pnotify.custom.min',
+ 'moment': 'libs/moment/js/moment.min',
+ 'moment-timezone': 'libs/moment-timezone/moment-timezone-with-data.min',
+ 'jquery-ui': 'external_lib/jquery-ui/jquery-ui.min',
+ 'jstree': 'libs/jstree/jstree.min',
+ 'd3': 'libs/d3/d3.min'
+ },
+
+ /**
+ * If set to true, an error will be thrown if a script loads that does not
+ * call define() or have a shim exports string value that can be checked.
+ * To get timely, correct error triggers in IE, force a define/shim export.
+ * @type {Boolean}
+ */
+ 'enforceDefine': false
+});
+
+require([
+ 'marionette',
+ 'utils/Helper',
+ 'bootstrap'
+], function(Marionette, Helper) {
+ var that = this;
+ var App = new Marionette.Application();
+
+ App.addRegions({
+ rContent: '.page-wrapper'
+ });
+
+ App.addInitializer(function() {
+ Backbone.history.start();
+ });
+ var Router = Backbone.Router.extend({
+ routes: {
+ // Define some URL routes
+ "": "defaultAction",
+ // Default
+ "*actions": "defaultAction"
+ },
+ initialize: function(options) {},
+ showRegions: function() {},
+ execute: function(callback, args) {
+ this.preRouteExecute();
+ if (callback) callback.apply(this, args);
+ this.postRouteExecute();
+ },
+ preRouteExecute: function() {},
+ postRouteExecute: function(name, args) {},
+ defaultAction: function() {
+ require(["views/migration/MigrationView"], function(MigrationView) {
+ App.rContent.show(new MigrationView());
+ });
+ }
+ });
+ App.appRouter = new Router({
+ entityDefCollection: this.entityDefCollection,
+ });
+ App.start();
+});
\ No newline at end of file
diff --git a/dashboardv2/public/js/templates/migration/MigrationView_tmpl.html b/dashboardv2/public/js/templates/migration/MigrationView_tmpl.html
new file mode 100644
index 0000000..41a665f
--- /dev/null
+++ b/dashboardv2/public/js/templates/migration/MigrationView_tmpl.html
@@ -0,0 +1,17 @@
+<!--
+ * 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.
+-->
+<div id="r_statisticsView" style="padding-top:30px;"></div>
\ No newline at end of file
diff --git a/dashboardv2/public/js/utils/Helper.js b/dashboardv2/public/js/utils/Helper.js
index 0ce8783..97c204b 100644
--- a/dashboardv2/public/js/utils/Helper.js
+++ b/dashboardv2/public/js/utils/Helper.js
@@ -114,94 +114,97 @@ define(['require',
$(this).blur();
});
- $.fn.select2.amd.define("ServiceTypeFilterDropdownAdapter", [
- "select2/utils",
- "select2/dropdown",
- "select2/dropdown/attachBody",
- "select2/dropdown/attachContainer",
- "select2/dropdown/search",
- "select2/dropdown/minimumResultsForSearch",
- "select2/dropdown/closeOnSelect",
- ],
- function(Utils, Dropdown, AttachBody, AttachContainer, Search, MinimumResultsForSearch, CloseOnSelect) {
+ if ($.fn.select2) {
+ $.fn.select2.amd.define("ServiceTypeFilterDropdownAdapter", [
+ "select2/utils",
+ "select2/dropdown",
+ "select2/dropdown/attachBody",
+ "select2/dropdown/attachContainer",
+ "select2/dropdown/search",
+ "select2/dropdown/minimumResultsForSearch",
+ "select2/dropdown/closeOnSelect",
+ ],
+ function(Utils, Dropdown, AttachBody, AttachContainer, Search, MinimumResultsForSearch, CloseOnSelect) {
- // Decorate Dropdown with Search functionalities
- var dropdownWithSearch = Utils.Decorate(Utils.Decorate(Dropdown, CloseOnSelect), Search);
+ // Decorate Dropdown with Search functionalities
+ var dropdownWithSearch = Utils.Decorate(Utils.Decorate(Dropdown, CloseOnSelect), Search);
- dropdownWithSearch.prototype.render = function() {
- // Copy and modify default search render method
- var $rendered = Dropdown.prototype.render.call(this);
+ dropdownWithSearch.prototype.render = function() {
+ // Copy and modify default search render method
+ var $rendered = Dropdown.prototype.render.call(this);
- // Add ability for a placeholder in the search box
- var placeholder = this.options.get("placeholderForSearch") || "";
- var $search = $(
- '<span class="select2-search select2-search--dropdown"><div class="row">' +
- '<div class="col-md-10"><input class="select2-search__field" placeholder="' + placeholder + '" type="search"' +
- ' tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off"' +
- ' spellcheck="false" role="textbox" /></div>' +
- '<div class="col-md-2"><button type="button" style="margin-left: -20px" class="btn btn-action btn-sm filter " title="Type Filter"><i class="fa fa-filter"></i></button></div>' +
- '</div></span>'
- );
- if (!this.options.options.getFilterBox) {
- throw "In order to render the filter options adapter needed getFilterBox function"
- }
- var $Filter = $('<ul class="type-filter-ul"></ul>');
- this.$Filter = $Filter;
- this.$Filter.append(this.options.options.getFilterBox());
- this.$Filter.hide();
+ // Add ability for a placeholder in the search box
+ var placeholder = this.options.get("placeholderForSearch") || "";
+ var $search = $(
+ '<span class="select2-search select2-search--dropdown"><div class="row">' +
+ '<div class="col-md-10"><input class="select2-search__field" placeholder="' + placeholder + '" type="search"' +
+ ' tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off"' +
+ ' spellcheck="false" role="textbox" /></div>' +
+ '<div class="col-md-2"><button type="button" style="margin-left: -20px" class="btn btn-action btn-sm filter " title="Type Filter"><i class="fa fa-filter"></i></button></div>' +
+ '</div></span>'
+ );
+ if (!this.options.options.getFilterBox) {
+ throw "In order to render the filter options adapter needed getFilterBox function"
+ }
+ var $Filter = $('<ul class="type-filter-ul"></ul>');
+ this.$Filter = $Filter;
+ this.$Filter.append(this.options.options.getFilterBox());
+ this.$Filter.hide();
- this.$searchContainer = $search;
- if ($Filter.find('input[type="checkbox"]:checked').length) {
- $search.find('button.filter').addClass('active');
- } else {
- $search.find('button.filter').removeClass('active');
- }
- this.$search = $search.find('input');
+ this.$searchContainer = $search;
+ if ($Filter.find('input[type="checkbox"]:checked').length) {
+ $search.find('button.filter').addClass('active');
+ } else {
+ $search.find('button.filter').removeClass('active');
+ }
+ this.$search = $search.find('input');
- $rendered.prepend($search);
- $rendered.append($Filter);
- return $rendered;
- };
- var oldDropdownWithSearchBindRef = dropdownWithSearch.prototype.bind;
- dropdownWithSearch.prototype.bind = function(container, $container) {
- var self = this;
- oldDropdownWithSearchBindRef.call(this, container, $container);
- var self = this;
- this.$Filter.on('click', 'li', function() {
- var itemCallback = self.options.options.onFilterItemSelect;
- itemCallback && itemCallback(this);
- })
+ $rendered.prepend($search);
+ $rendered.append($Filter);
+ return $rendered;
+ };
+ var oldDropdownWithSearchBindRef = dropdownWithSearch.prototype.bind;
+ dropdownWithSearch.prototype.bind = function(container, $container) {
+ var self = this;
+ oldDropdownWithSearchBindRef.call(this, container, $container);
+ var self = this;
+ this.$Filter.on('click', 'li', function() {
+ var itemCallback = self.options.options.onFilterItemSelect;
+ itemCallback && itemCallback(this);
+ })
- this.$searchContainer.find('button.filter').click(function() {
- container.$dropdown.find('.select2-search').hide(150);
- container.$dropdown.find('.select2-results').hide(150);
- self.$Filter.html(self.options.options.getFilterBox());
- self.$Filter.show();
- });
- this.$Filter.on('click', 'button.filterDone', function() {
- container.$dropdown.find('.select2-search').show(150);
- container.$dropdown.find('.select2-results').show(150);
- self.$Filter.hide();
- var filterSubmitCallback = self.options.options.onFilterSubmit;
- filterSubmitCallback && filterSubmitCallback({
- filterVal: _.map(self.$Filter.find('input[type="checkbox"]:checked'), function(item) {
- return $(item).data('value')
- })
+ this.$searchContainer.find('button.filter').click(function() {
+ container.$dropdown.find('.select2-search').hide(150);
+ container.$dropdown.find('.select2-results').hide(150);
+ self.$Filter.html(self.options.options.getFilterBox());
+ self.$Filter.show();
+ });
+ this.$Filter.on('click', 'button.filterDone', function() {
+ container.$dropdown.find('.select2-search').show(150);
+ container.$dropdown.find('.select2-results').show(150);
+ self.$Filter.hide();
+ var filterSubmitCallback = self.options.options.onFilterSubmit;
+ filterSubmitCallback && filterSubmitCallback({
+ filterVal: _.map(self.$Filter.find('input[type="checkbox"]:checked'), function(item) {
+ return $(item).data('value')
+ })
+ });
+ });
+ container.$element.on('hideFilter', function() {
+ container.$dropdown.find('.select2-search').show();
+ container.$dropdown.find('.select2-results').show();
+ self.$Filter.hide();
});
- });
- container.$element.on('hideFilter', function() {
- container.$dropdown.find('.select2-search').show();
- container.$dropdown.find('.select2-results').show();
- self.$Filter.hide();
- });
- }
- // Decorate the dropdown+search with necessary containers
- var adapter = Utils.Decorate(dropdownWithSearch, AttachContainer);
- adapter = Utils.Decorate(adapter, AttachBody);
+ }
+ // Decorate the dropdown+search with necessary containers
+ var adapter = Utils.Decorate(dropdownWithSearch, AttachContainer);
+ adapter = Utils.Decorate(adapter, AttachBody);
+
+ return adapter;
+ });
+ }
- return adapter;
- });
$.widget("custom.atlasAutoComplete", $.ui.autocomplete, {
_create: function() {
diff --git a/dashboardv2/public/js/views/migration/MigrationView.js b/dashboardv2/public/js/views/migration/MigrationView.js
new file mode 100644
index 0000000..8f4b0b0
--- /dev/null
+++ b/dashboardv2/public/js/views/migration/MigrationView.js
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+define(['require',
+ 'backbone',
+ 'hbs!tmpl/migration/MigrationView_tmpl'
+], function(require, Backbone, MigrationViewTmpl) {
+ 'use strict';
+
+ var ProfileLayoutView = Backbone.Marionette.LayoutView.extend(
+ /** @lends ProfileLayoutView */
+ {
+ _viewName: 'MigrationView',
+
+ template: MigrationViewTmpl,
+
+ /** Layout sub regions */
+ regions: {
+ RStatisticsView: "#r_statisticsView",
+ },
+ /** ui selector cache */
+ ui: {},
+ /** ui events hash */
+ events: function() {},
+ /**
+ * intialize a new ProfileLayoutView Layout
+ * @constructs
+ */
+ initialize: function(options) {
+ this.apiBaseUrl = this.getBaseUrl(window.location.pathname);
+ },
+ bindEvents: function() {},
+ getBaseUrl: function(url) {
+ var path = url.replace(/\/[\w-]+.(jsp|html)|\/+$/ig, ''),
+ splitPath = path.split("/");
+ if (splitPath && splitPath[splitPath.length - 1] === "n") {
+ splitPath.pop();
+ return splitPath.join("/");
+ }
+ return path;
+ },
+ onRender: function() {
+ var that = this;
+ require(["views/site/Statistics", "collection/VTagList", "utils/UrlLinks"], function(Statistics, VTagList, UrlLinks) {
+ that.metricCollection = new VTagList();
+ that.metricCollection.url = UrlLinks.metricsApiUrl();
+ that.metricCollection.modelAttrName = "data";
+ that.RStatisticsView.show(new Statistics({ hideModal: false, metricCollection: that.metricCollection }));
+ })
+ }
+ });
+ return ProfileLayoutView;
+});
\ No newline at end of file
diff --git a/dashboardv2/public/js/views/site/Statistics.js b/dashboardv2/public/js/views/site/Statistics.js
index 0329e04..93cc87e 100644
--- a/dashboardv2/public/js/views/site/Statistics.js
+++ b/dashboardv2/public/js/views/site/Statistics.js
@@ -67,34 +67,39 @@ define(['require',
_.extend(this, options);
var that = this;
this.DATA_MAX_LENGTH = 25;
- var modal = new Modal({
- title: 'Statistics',
- content: this,
- okCloses: true,
- okText: "Close",
- showFooter: true,
- allowCancel: false,
- width: "60%",
- headerButtons: [{
- title: "Refresh Data",
- btnClass: "fa fa-refresh",
- onClick: function() {
- modal.$el.find('.header-button .fa-refresh').tooltip('hide').prop('disabled', true).addClass('fa-spin');
- that.fetchMetricData({ update: true });
- }
- }]
- }).open();
+ if (this.hideModal !== false) {
+ var modal = new Modal({
+ title: 'Statistics',
+ content: this,
+ okCloses: true,
+ okText: "Close",
+ showFooter: true,
+ allowCancel: false,
+ width: "60%",
+ headerButtons: [{
+ title: "Refresh Data",
+ btnClass: "fa fa-refresh",
+ onClick: function() {
+ modal.$el.find('.header-button .fa-refresh').tooltip('hide').prop('disabled', true).addClass('fa-spin');
+ that.fetchMetricData({ update: true });
+ }
+ }]
+ }).open();
+
+ modal.on('closeModal', function() {
+ modal.trigger('cancel');
+ });
+ this.modal = modal;
+ }
- modal.on('closeModal', function() {
- modal.trigger('cancel');
- });
- this.modal = modal;
},
bindEvents: function() {
var that = this;
- this.$el.on('click', '.linkClicked', function() {
- that.modal.close();
- })
+ if (this.modal) {
+ this.$el.on('click', '.linkClicked', function() {
+ that.modal.close();
+ })
+ }
},
fetchMetricData: function(options) {
var that = this;
@@ -109,7 +114,9 @@ define(['require',
that.$('.statsContainer,.statsNotificationContainer').removeClass('hide');
that.$('.statsLoader,.statsNotificationLoader').removeClass('show');
if (options && options.update) {
- that.modal.$el.find('.header-button .fa-refresh').prop('disabled', false).removeClass('fa-spin');
+ if (that.modal) {
+ that.modal.$el.find('.header-button .fa-refresh').prop('disabled', false).removeClass('fa-spin');
+ }
Utils.notifySuccess({
content: "Metric data is refreshed"
})
diff --git a/dashboardv2/public/migration-status.html.tpl b/dashboardv2/public/migration-status.html.tpl
new file mode 100644
index 0000000..0048826
--- /dev/null
+++ b/dashboardv2/public/migration-status.html.tpl
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<!--
+ * 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.
+-->
+<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
+<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
+<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
+<!--[if gt IE 7]>
+ <script src="js/external_lib/es5-shim.min.js?bust=<%- bust %>"></script>
+ <script src="js/external_lib/respond.min.js?bust=<%- bust %>"></script>
+<![endif]-->
+<!--[if gt IE 8]><!-->
+<html class="no-js">
+<!--<![endif]-->
+
+<head>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8;" />
+ <title>Atlas</title>
+ <meta name="description" content="" />
+ <meta name="viewport" content="width=device-width" />
+ <link rel="shortcut icon" href="img/favicon.ico?bust=<%- bust %>" type="image/x-icon" />
+ <link rel="icon" href="img/favicon.ico?bust=<%- bust %>" type="image/x-icon" />
+ <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
+ <link rel="stylesheet" type="text/css" href="css/animate.min.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="js/libs/backgrid/css/backgrid.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="js/libs/backgrid-filter/css/backgrid-filter.min.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="js/libs/backgrid-paginator/css/backgrid-paginator.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="js/libs/backgrid-orderable-columns/css/backgrid-orderable-columns.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="js/libs/backgrid-sizeable-columns/css/backgrid-sizeable-columns.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="js/external_lib/backgrid-columnmanager/css/Backgrid.ColumnManager.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="js/libs/select2/css/select2.min.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="js/libs/bootstrap/css/bootstrap.min.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="js/libs/jquery-asBreadcrumbs/css/asBreadcrumbs.min.css?bust=<%- bust %>" />
+ <link rel="stylesheet" href="css/googlefonts.css?bust=<%- bust %>" type="text/css" />
+ <link rel="stylesheet" type="text/css" href="js/external_lib/jquery-ui/jquery-ui.min.css?bust=<%- bust %>" />
+ <link href="css/bootstrap-sidebar.css?bust=<%- bust %>" rel="stylesheet" />
+ <link href="js/libs/font-awesome/css/font-awesome.min.css?bust=<%- bust %>" rel="stylesheet" />
+ <link href="js/external_lib/pnotify/pnotify.custom.min.css?bust=<%- bust %>" rel="stylesheet" />
+ <link href="js/libs/jQueryQueryBuilder/css/query-builder.default.min.css?bust=<%- bust %>" rel="stylesheet" />
+ <link href="js/libs/bootstrap-daterangepicker/css/daterangepicker.css?bust=<%- bust %>" rel="stylesheet" />
+ <link rel="stylesheet" href="js/libs/nvd3/css/nv.d3.min.css?bust=<%- bust %>" />
+ <link href="js/libs/jstree/css/default/default-theme.min.css?bust=<%- bust %>" rel="stylesheet" />
+ <link href="js/libs/pretty-checkbox/css/pretty-checkbox.min.css?bust=<%- bust %>" rel="stylesheet" />
+ <link href="css/style.css?bust=<%- bust %>" rel="stylesheet" />
+</head>
+
+<body>
+ <div class="container-fluid">
+ <div class="col-sm-12">
+ <div class="page-wrapper">
+ <div class="initialLoading"></div>
+ </div>
+ </div>
+ </div>
+ <!-- build:js scripts/main.js -->
+ <script data-main="js/migration.js?bust=<%- bust %>" src="js/libs/requirejs/require.js?bust=<%- bust %>"></script>
+ <!-- endbuild -->
+ <script type="text/javascript">
+ var getBustValue = function() {
+ return "<%- bust %>";
+ };
+ </script>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/webapp/src/main/java/org/apache/atlas/web/filters/ActiveServerFilter.java b/webapp/src/main/java/org/apache/atlas/web/filters/ActiveServerFilter.java
index 4d452e4..2c28aaf 100644
--- a/webapp/src/main/java/org/apache/atlas/web/filters/ActiveServerFilter.java
+++ b/webapp/src/main/java/org/apache/atlas/web/filters/ActiveServerFilter.java
@@ -50,6 +50,8 @@ import java.io.IOException;
public class ActiveServerFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(ActiveServerFilter.class);
+ private static final String MIGRATION_STATUS_STATIC_PAGE = "migration-status.html";
+
private final ActiveInstanceState activeInstanceState;
private ServiceState serviceState;
@@ -88,6 +90,9 @@ public class ActiveServerFilter implements Filter {
LOG.error("Instance in transition. Service may not be ready to return a result");
httpServletResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
} else if (serviceState.isInstanceInMigration()) {
+ if (isRootURI(servletRequest)) {
+ handleMigrationRedirect(servletRequest, servletResponse);
+ }
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
LOG.error("Instance in migration. Service may not be ready to return a result");
httpServletResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
@@ -123,10 +128,30 @@ public class ActiveServerFilter implements Filter {
}
}
+ private boolean isRootURI(ServletRequest servletRequest) {
+ HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+ String requestURI = httpServletRequest.getRequestURI();
+ return requestURI.equals("/");
+ }
+
boolean isInstanceActive() {
return serviceState.getState() == ServiceState.ServiceStateValue.ACTIVE;
}
+ private void handleMigrationRedirect(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
+
+ HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
+ HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+
+ String redirectLocation = httpServletRequest.getRequestURL() + MIGRATION_STATUS_STATIC_PAGE;
+ if (isUnsafeHttpMethod(httpServletRequest)) {
+ httpServletResponse.setHeader(HttpHeaders.LOCATION, redirectLocation);
+ httpServletResponse.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT);
+ } else {
+ httpServletResponse.sendRedirect(redirectLocation);
+ }
+ }
+
private void handleRedirect(HttpServletRequest servletRequest, HttpServletResponse httpServletResponse,
String activeServerAddress) throws IOException {
String requestURI = servletRequest.getRequestURI();
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java b/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
index c3565d4..498c0aa 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
+++ b/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
@@ -168,6 +168,7 @@ public class AtlasSecurityConfig extends WebSecurityConfigurerAdapter {
"/js/**",
"/n/js/**",
"/ieerror.html",
+ "/migration-status.html",
"/api/atlas/admin/status",
"/api/atlas/admin/metrics"));