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"));