You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ha...@apache.org on 2020/06/19 14:00:52 UTC

[ambari] branch trunk updated: [AMBARI-25208] : Enable/Disable HBase Cross Cluster Replication (without common-service changes for trunk) (#3014) (virajjasani via dgrinenko)

This is an automated email from the ASF dual-hosted git repository.

hapylestat pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/trunk by this push:
     new a42d52f  [AMBARI-25208] : Enable/Disable HBase Cross Cluster Replication (without common-service changes for trunk) (#3014) (virajjasani via dgrinenko)
a42d52f is described below

commit a42d52f7999592c96f67ad114d27f7b8a2a92e66
Author: Viraj Jasani <vi...@gmail.com>
AuthorDate: Fri Jun 19 19:30:42 2020 +0530

    [AMBARI-25208] : Enable/Disable HBase Cross Cluster Replication (without common-service changes for trunk) (#3014) (virajjasani via dgrinenko)
---
 .../BackgroundCustomCommandExecutionTest.java      | 102 ++++++++++++++-
 .../stacks/HDP/2.0.5/services/HBASE/metainfo.xml   |  16 +++
 ambari-web/app/controllers/main/service/item.js    | 140 +++++++++++++++++++++
 ambari-web/app/messages.js                         |  15 +++
 ambari-web/app/models/host_component.js            |  16 +++
 ambari-web/app/styles/alerts.less                  |  20 +++
 ambari-web/app/styles/application.less             |   3 +
 .../modal_popups/update_replication_popup.hbs      |  61 +++++++++
 ambari-web/app/utils/ajax/ajax.js                  |  51 ++++++++
 ambari-web/app/views/main/service/item.js          |  14 ++-
 10 files changed, 433 insertions(+), 5 deletions(-)

diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
index 89d0630..c979984 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
@@ -77,6 +77,13 @@ public class BackgroundCustomCommandExecutionTest {
   private Clusters clusters;
 
   private static final String REQUEST_CONTEXT_PROPERTY = "context";
+  private static final String UPDATE_REPLICATION_PARAMS = "{\n" +
+          "              \"replication_cluster_keys\": c7007.ambari.apache.org,c7008.ambari.apache.org,c7009.ambari.apache.org:2181:/hbase,\n" +
+          "              \"replication_peers\": 1\n" +
+          "            }";
+  private static final String STOP_REPLICATION_PARAMS = "{\n" +
+          "              \"replication_peers\": 1\n" +
+          "            }";
 
   @Captor ArgumentCaptor<Request> requestCapture;
   @Mock ActionManager am;
@@ -180,15 +187,18 @@ public class BackgroundCustomCommandExecutionTest {
     createCluster("c1");
     addHost("c6401","c1");
     addHost("c6402","c1");
+    addHost("c7007", "c1");
     clusters.updateHostMappings(clusters.getHost("c6401"));
     clusters.updateHostMappings(clusters.getHost("c6402"));
+    clusters.updateHostMappings(clusters.getHost("c7007"));
 
     clusters.getCluster("c1");
     createService("c1", "HDFS", null);
-
-    createServiceComponent("c1","HDFS","NAMENODE", State.INIT);
-
-    createServiceComponentHost("c1","HDFS","NAMENODE","c6401", null);
+    createService("c1", "HBASE", null);
+    createServiceComponent("c1", "HDFS", "NAMENODE", State.INIT);
+    createServiceComponent("c1", "HBASE", "HBASE_MASTER", State.INIT);
+    createServiceComponentHost("c1", "HDFS", "NAMENODE", "c6401", null);
+    createServiceComponentHost("c1", "HBASE", "HBASE_MASTER", "c7007", null);
   }
   private void addHost(String hostname, String clusterName) throws AmbariException {
     clusters.addHost(hostname);
@@ -206,6 +216,90 @@ public class BackgroundCustomCommandExecutionTest {
     host.setHostAttributes(hostAttributes);
   }
 
+
+  @SuppressWarnings("serial")
+  @Test
+  public void testUpdateHBaseReplicationCustomCommand()
+          throws AuthorizationException, AmbariException, IllegalAccessException,
+          NoSuchFieldException {
+    createClusterFixture();
+    Map<String, String> requestProperties = new HashMap<String, String>() {
+      {
+        put(REQUEST_CONTEXT_PROPERTY, "Enable Cross Cluster HBase Replication");
+        put("command", "UPDATE_REPLICATION");
+        put("parameters", UPDATE_REPLICATION_PARAMS);
+      }
+    };
+    ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1",
+            "UPDATE_REPLICATION", new HashMap<>(), false);
+    actionRequest.getResourceFilters().add(new RequestResourceFilter("HBASE", "HBASE_MASTER",
+            Collections.singletonList("c7007")));
+
+    controller.createAction(actionRequest, requestProperties);
+
+    Mockito.verify(am, Mockito.times(1))
+            .sendActions(requestCapture.capture(), any(ExecuteActionRequest.class));
+
+    Request request = requestCapture.getValue();
+    Assert.assertNotNull(request);
+    Assert.assertNotNull(request.getStages());
+    Assert.assertEquals(1, request.getStages().size());
+    Stage stage = request.getStages().iterator().next();
+
+    Assert.assertEquals(1, stage.getHosts().size());
+
+    List<ExecutionCommandWrapper> commands = stage.getExecutionCommands("c7007");
+    Assert.assertEquals(1, commands.size());
+    ExecutionCommand command = commands.get(0).getExecutionCommand();
+    Assert.assertEquals(AgentCommandType.EXECUTION_COMMAND, command.getCommandType());
+    Assert.assertEquals("UPDATE_REPLICATION", command.getCommandParams().get("custom_command"));
+
+  }
+
+
+
+  @SuppressWarnings("serial")
+  @Test
+  public void testStopHBaseReplicationCustomCommand()
+          throws AuthorizationException, AmbariException, IllegalAccessException,
+          NoSuchFieldException {
+    createClusterFixture();
+    Map<String, String> requestProperties = new HashMap<String, String>() {
+      {
+        put(REQUEST_CONTEXT_PROPERTY, "Disable Cross Cluster HBase Replication");
+        put("command", "STOP_REPLICATION");
+        put("parameters", STOP_REPLICATION_PARAMS);
+      }
+    };
+    ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1",
+            "STOP_REPLICATION", new HashMap<>(), false);
+    actionRequest.getResourceFilters().add(new RequestResourceFilter("HBASE", "HBASE_MASTER",
+            Collections.singletonList("c7007")));
+
+    controller.createAction(actionRequest, requestProperties);
+
+    Mockito.verify(am, Mockito.times(1))
+            .sendActions(requestCapture.capture(), any(ExecuteActionRequest.class));
+
+    Request request = requestCapture.getValue();
+    Assert.assertNotNull(request);
+    Assert.assertNotNull(request.getStages());
+    Assert.assertEquals(1, request.getStages().size());
+    Stage stage = request.getStages().iterator().next();
+
+    Assert.assertEquals(1, stage.getHosts().size());
+
+    List<ExecutionCommandWrapper> commands = stage.getExecutionCommands("c7007");
+    Assert.assertEquals(1, commands.size());
+    ExecutionCommand command = commands.get(0).getExecutionCommand();
+    Assert.assertEquals(AgentCommandType.EXECUTION_COMMAND, command.getCommandType());
+    Assert.assertEquals("STOP_REPLICATION", command.getCommandParams().get("custom_command"));
+
+  }
+
+
+
+
   private void createCluster(String clusterName) throws AmbariException, AuthorizationException {
     ClusterRequest r = new ClusterRequest(null, clusterName, State.INSTALLED.name(),
         SecurityType.NONE, STACK_ID.getStackId(), null);
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HBASE/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HBASE/metainfo.xml
index 322a190..57e6125 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HBASE/metainfo.xml
+++ b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HBASE/metainfo.xml
@@ -59,6 +59,22 @@
                 <timeout>600</timeout>
               </commandScript>
             </customCommand>
+            <customCommand>
+              <name>UPDATE_REPLICATION</name>
+              <commandScript>
+                <script>scripts/hbase_master.py</script>
+                <scriptType>PYTHON</scriptType>
+                <timeout>600</timeout>
+              </commandScript>
+            </customCommand>
+            <customCommand>
+              <name>STOP_REPLICATION</name>
+              <commandScript>
+                <script>scripts/hbase_master.py</script>
+                <scriptType>PYTHON</scriptType>
+                <timeout>600</timeout>
+              </commandScript>
+            </customCommand>
           </customCommands>
         </component>
 
diff --git a/ambari-web/app/controllers/main/service/item.js b/ambari-web/app/controllers/main/service/item.js
index 0a7f1e3..d749c31 100644
--- a/ambari-web/app/controllers/main/service/item.js
+++ b/ambari-web/app/controllers/main/service/item.js
@@ -937,6 +937,146 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow
     });
   },
 
+  /**
+   * On click handler for Update HBase Replication command from items menu
+   */
+  updateHBaseReplication: function () {
+    const controller = this;
+    App.ModalPopup.show({
+      classNames: ['sixty-percent-width-modal', 'service-params-popup'],
+      header: Em.I18n.t('services.service.actions.run.updateHBaseReplication.context'),
+      primary: Em.I18n.t('common.start'),
+      secondary: Em.I18n.t('common.cancel'),
+      peerId: '',
+      parentzkey: '/hbase',
+      zkport: '2181',
+      zkquorum: '',
+      errorMessage: Em.I18n.t('services.service.actions.run.updateHBaseReplication.promptError'),
+      isInvalid: function () {
+        const zkquorum = this.get('zkquorum');
+        const zkport = this.get('zkport');
+        const parentzkey = this.get('parentzkey');
+        const peerId = this.get('peerId');
+        if (zkquorum && zkport && parentzkey && peerId) {
+          if (isNaN(zkport) || isNaN(peerId)) {
+            return true;
+          }
+          const zkquorumArray = zkquorum.split(',');
+          return zkquorumArray.length < 2;
+        } else {
+          return true;
+        }
+      }.property('zkquorum', 'zkport', 'parentzkey', 'peerId'),
+      disablePrimary: Em.computed.alias('isInvalid'),
+      onPrimary: function () {
+        if (this.get('isInvalid')) {
+          return;
+        }
+        App.ajax.send({
+          name: 'service.item.updateHBaseReplication',
+          sender: controller,
+          data: {
+            hosts: App.Service.find('HBASE').get('hostComponents').findProperty('componentName', 'HBASE_MASTER').get('hostName'),
+            replication_peers: this.get('peerId'),
+            replication_cluster_keys: this.get('zkquorum') + ':' + this.get('zkport') + ":" + this.get('parentzkey')
+          },
+          success: 'updateHBaseReplicationSuccessCallback',
+          error: 'updateHBaseReplicationErrorCallback',
+          showLoadingPopup: true
+        });
+        this.hide();
+      },
+      bodyClass: Ember.View.extend({
+        templateName: require('templates/common/modal_popups/update_replication_popup'),
+        zkquorumText: Em.I18n.t('services.service.actions.run.updateHBaseReplication.zkquorumText.prompt'),
+        zkportText: Em.I18n.t('services.service.actions.run.updateHBaseReplication.zkportText.prompt'),
+        parentzkeyText: Em.I18n.t('services.service.actions.run.updateHBaseReplication.parentzkeyText.prompt'),
+        peerIdText: Em.I18n.t('services.service.actions.run.updateHBaseReplication.peerIdText.prompt')
+      })
+    });
+  },
+
+  updateHBaseReplicationSuccessCallback: function (data) {
+    if (data.Requests.id) {
+      App.router.get('backgroundOperationsController').showPopup();
+    }
+  },
+
+  updateHBaseReplicationErrorCallback: function (data) {
+    var error = Em.I18n.t('services.service.actions.run.updateHBaseReplication.error');
+    if (data && data.responseText) {
+      try {
+        const json = $.parseJSON(data.responseText);
+        error += json.message;
+      } catch (err) {
+        console.log(err);
+      }
+    }
+    App.showAlertPopup(Em.I18n.t('services.service.actions.run.updateHBaseReplication.error'), error);
+  },
+
+
+  /**
+   * On click handler for Stop HBase Replication command from items menu
+   */
+  stopHBaseReplication: function () {
+    const controller = this;
+    App.ModalPopup.show({
+      classNames: ['forty-percent-width-modal'],
+      header: Em.I18n.t('services.service.actions.run.stopHBaseReplication.context'),
+      primary: Em.I18n.t('common.start'),
+      secondary: Em.I18n.t('common.cancel'),
+      inputValue: '',
+      errorMessage: Em.I18n.t('services.service.actions.run.stopHBaseReplication.promptError'),
+      isInvalid: function () {
+        const inputValue = this.get('inputValue');
+        return !inputValue || isNaN(inputValue);
+      }.property('inputValue'),
+      disablePrimary: Em.computed.alias('isInvalid'),
+      onPrimary: function () {
+        if (this.get('isInvalid')) {
+          return;
+        }
+        App.ajax.send({
+          name: 'service.item.stopHBaseReplication',
+          sender: controller,
+          data: {
+            hosts: App.Service.find('HBASE').get('hostComponents').findProperty('componentName', 'HBASE_MASTER').get('hostName'),
+            replication_peers: this.get('inputValue')
+          },
+          success: 'stopHBaseReplicationSuccessCallback',
+          error: 'stopHBaseReplicationErrorCallback',
+          showLoadingPopup: true
+        });
+        this.hide();
+      },
+      bodyClass: Ember.View.extend({
+        templateName: require('templates/common/modal_popups/prompt_popup'),
+        text: Em.I18n.t('services.service.actions.run.stopHBaseReplication.prompt'),
+      })
+    });
+  },
+
+  stopHBaseReplicationSuccessCallback: function (data) {
+    if (data.Requests.id) {
+      App.router.get('backgroundOperationsController').showPopup();
+    }
+  },
+
+  stopHBaseReplicationErrorCallback: function (data) {
+    var error = Em.I18n.t('services.service.actions.run.stopHBaseReplication.error');
+    if (data && data.responseText) {
+      try {
+        const json = $.parseJSON(data.responseText);
+        error += json.message;
+      } catch (err) {
+        console.log(err);
+      }
+    }
+    App.showAlertPopup(Em.I18n.t('services.service.actions.run.stopHBaseReplication.error'), error);
+  },
+
+
   restartAllHostComponents: function (serviceName) {
     const serviceDisplayName = this.get('content.displayName'),
       bodyMessage = Em.Object.create({
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index cc8e159..89a8f15 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -2111,6 +2111,21 @@ Em.I18n.translations = {
   'services.service.actions.run.stopLdapKnox.title':'Stop Demo LDAP Knox Gateway',
   'services.service.actions.run.stopLdapKnox.context':'Stop Demo LDAP',
   'services.service.actions.run.startStopLdapKnox.error': 'Error during remote command: ',
+  'services.service.actions.run.updateHBaseReplication.label': 'Start/Update HBase Replication',
+  'services.service.actions.run.updateHBaseReplication.context': 'Enable Cross Cluster HBase Replication',
+  'services.service.actions.run.updateHBaseReplication.title': 'HBase Replication: Start/Update',
+  'services.service.actions.run.updateHBaseReplication.promptError': 'ZKQuorum should be comma(,) separated ZK nodes. Port and Peer ID should be number',
+  'services.service.actions.run.updateHBaseReplication.zkquorumText.prompt': 'Peer Cluster ZK Quorum: ',
+  'services.service.actions.run.updateHBaseReplication.zkportText.prompt': 'Peer Cluster ZK Port: ',
+  'services.service.actions.run.updateHBaseReplication.parentzkeyText.prompt': 'Parent ZKey for HBase: ',
+  'services.service.actions.run.updateHBaseReplication.peerIdText.prompt': 'Peer Cluster ID: ',
+  'services.service.actions.run.updateHBaseReplication.error':'Error while setting up HBase Cross Cluster Replication ',
+  'services.service.actions.run.stopHBaseReplication.label': 'Stop HBase Replication',
+  'services.service.actions.run.stopHBaseReplication.context': 'Disable Cross Cluster HBase Replication',
+  'services.service.actions.run.stopHBaseReplication.title': 'HBase Replication: Stop',
+  'services.service.actions.run.stopHBaseReplication.promptError': 'Peer ID should be number',
+  'services.service.actions.run.stopHBaseReplication.error': 'Error while disabling HBase Cross Cluster Replication ',
+  'services.service.actions.run.stopHBaseReplication.prompt': 'Peer Cluster ID to remove from Replication Peer list: ',
 
   // Hive Server Interactive custom command to restart LLAP
   'services.service.actions.run.restartLLAP':'Restart LLAP',
diff --git a/ambari-web/app/models/host_component.js b/ambari-web/app/models/host_component.js
index 92014ba..87a6439 100644
--- a/ambari-web/app/models/host_component.js
+++ b/ambari-web/app/models/host_component.js
@@ -574,6 +574,22 @@ App.HostComponentActionMap = {
         label: Em.I18n.t('admin.nameNodeFederation.button.enable'),
         cssClass: 'icon icon-sitemap',
         disabled: !App.get('isHaEnabled')
+      },
+      UPDATE_REPLICATION: {
+        action: 'updateHBaseReplication',
+        customCommand: 'UPDATE_REPLICATION',
+        context: Em.I18n.t('services.service.actions.run.updateHBaseReplication.context'),
+        label: Em.I18n.t('services.service.actions.run.updateHBaseReplication.label'),
+        cssClass: 'glyphicon glyphicon-refresh',
+        disabled: false
+      },
+      STOP_REPLICATION: {
+        action: 'stopHBaseReplication',
+        customCommand: 'STOP_REPLICATION',
+        context: Em.I18n.t('services.service.actions.run.stopHBaseReplication.context'),
+        label: Em.I18n.t('services.service.actions.run.stopHBaseReplication.label'),
+        cssClass: 'glyphicon glyphicon-refresh',
+        disabled: false
       }
     };
   },
diff --git a/ambari-web/app/styles/alerts.less b/ambari-web/app/styles/alerts.less
index 0bac6a4..2bdf6e0 100644
--- a/ambari-web/app/styles/alerts.less
+++ b/ambari-web/app/styles/alerts.less
@@ -496,6 +496,26 @@
   width: 95%;
 }
 
+.service-params-popup {
+  .modal {
+    .modal-dialog {
+      width: 55%;
+      .modal-content {
+        height: 60%;
+        .modal-body {
+          padding-left: 0;
+          padding-right: 0;
+          height: 75%;
+          font-size: 14px;
+          .definition-latest-text, .timeago {
+            font-size: 12px;
+          }
+        }
+      }
+    }
+  }
+}
+
 .alerts-popup-wrap {
   #alert-info {
     overflow: auto;
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index b3171fe..5bf9f4f 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -2082,6 +2082,9 @@ input[type="radio"].align-checkbox, input[type="checkbox"].align-checkbox {
   .prompt-input {
     width: 80px;
   }
+  .large-prompt-input {
+    width: 70%;
+  }
 }
 
 #views {
diff --git a/ambari-web/app/templates/common/modal_popups/update_replication_popup.hbs b/ambari-web/app/templates/common/modal_popups/update_replication_popup.hbs
new file mode 100644
index 0000000..ff1b19d
--- /dev/null
+++ b/ambari-web/app/templates/common/modal_popups/update_replication_popup.hbs
@@ -0,0 +1,61 @@
+{{!
+* 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 class="prompt-popup">
+    <form>
+        <div {{bindAttr class=":form-group view.parentView.isInvalid:has-error"}}>
+            <h4>{{view.title}}</h4>
+            <p>{{view.description}}</p>
+            <br/>
+            <label class="control-label">{{view.zkquorumText}}</label>
+            <div>
+                &nbsp;&nbsp;
+                {{view Em.TextField class="large-prompt-input form-control" valueBinding="view.parentView.zkquorum"}}
+            </div>
+            <br/>
+            <label class="control-label">{{view.zkportText}}</label>
+            <div>
+                &nbsp;&nbsp;
+                {{view Em.TextField class="prompt-input form-control" valueBinding="view.parentView.zkport"}}
+            </div>
+            <br/>
+            <label class="control-label">{{view.parentzkeyText}}</label>
+            <div>
+                &nbsp;&nbsp;
+                {{view Em.TextField class="prompt-input form-control" valueBinding="view.parentView.parentzkey"}}
+            </div>
+            <br/>
+            <label class="control-label">{{view.peerIdText}}</label>
+            <div>
+                &nbsp;&nbsp;
+                {{view Em.TextField class="prompt-input form-control" valueBinding="view.parentView.peerId"}}
+            </div>
+            <div>
+                {{#if view.parentView.isChanged}}
+                    <a href="#" data-toggle="tooltip" class="btn-sm"
+                        {{action "doRestoreDefaultValue" this target="view.parentView"}}
+                        {{translateAttr data-original-title="common.reset.default"}}>
+                        <i class="icon-undo"></i>
+                    </a>
+                {{/if}}
+            </div>
+            {{#if view.parentView.isInvalid}}
+                <span class="help-block validation-block">{{view.parentView.errorMessage}}</span>
+            {{/if}}
+        </div>
+    </form>
+</div>
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index 4b2cf98..dd34184 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -696,6 +696,57 @@ var urls = {
     }
   },
 
+  'service.item.updateHBaseReplication': {
+    'real': '/clusters/{clusterName}/requests',
+    'mock': '',
+    'format': function (data) {
+      return {
+        type: 'POST',
+        data: JSON.stringify({
+          RequestInfo: {
+            'context': Em.I18n.t('services.service.actions.run.updateHBaseReplication.context'),
+            'command': 'UPDATE_REPLICATION',
+            "parameters": {
+              "replication_cluster_keys": data.replication_cluster_keys,
+              "replication_peers": data.replication_peers
+            }
+          },
+          "Requests/resource_filters": [{
+            'service_name': 'HBASE',
+            'component_name': 'HBASE_MASTER',
+            'hosts': data.hosts
+          }]
+        })
+      }
+    }
+  },
+
+  'service.item.stopHBaseReplication': {
+    'real': '/clusters/{clusterName}/requests',
+    'mock': '',
+    'format': function (data) {
+      return {
+        type: 'POST',
+        data: JSON.stringify({
+          RequestInfo: {
+            'context': Em.I18n.t('services.service.actions.run.stopHBaseReplication.context'),
+            'command': 'STOP_REPLICATION',
+            "parameters": {
+              "replication_peers": data.replication_peers
+            }
+          },
+          "Requests/resource_filters": [{
+            'service_name': 'HBASE',
+            'component_name': 'HBASE_MASTER',
+            'hosts': data.hosts
+          }]
+        })
+      }
+    }
+  },
+
+
+
   'service.item.executeCustomCommand': {
     'real': '/clusters/{clusterName}/requests',
     'mock': '',
diff --git a/ambari-web/app/views/main/service/item.js b/ambari-web/app/views/main/service/item.js
index e256743..bb61663 100644
--- a/ambari-web/app/views/main/service/item.js
+++ b/ambari-web/app/views/main/service/item.js
@@ -35,7 +35,7 @@ App.MainServiceItemView = Em.View.extend(App.HiveInteractiveCheck, {
   mastersExcludedCommands: {
     'NAMENODE': ['DECOMMISSION', 'REBALANCEHDFS'],
     'RESOURCEMANAGER': ['DECOMMISSION', 'REFRESHQUEUES'],
-    'HBASE_MASTER': ['DECOMMISSION'],
+    'HBASE_MASTER': ['DECOMMISSION', 'UPDATE_REPLICATION', 'STOP_REPLICATION'],
     'KNOX_GATEWAY': ['STARTDEMOLDAP','STOPDEMOLDAP'],
     'HAWQMASTER': ['IMMEDIATE_STOP_HAWQ_SERVICE', 'RUN_HAWQ_CHECK', 'HAWQ_CLEAR_CACHE', 'REMOVE_HAWQ_STANDBY', 'RESYNC_HAWQ_STANDBY'],
     'HAWQSEGMENT': ['IMMEDIATE_STOP_HAWQ_SEGMENT'],
@@ -276,6 +276,18 @@ App.MainServiceItemView = Em.View.extend(App.HiveInteractiveCheck, {
           }
         }
 
+        const hMasterComponent = App.StackServiceComponent.find().findProperty('componentName', 'HBASE_MASTER');
+        if (serviceName === 'HBASE' && hMasterComponent) {
+          const hMasterCustomCommands = hMasterComponent.get('customCommands');
+          if (hMasterCustomCommands && hMasterCustomCommands.contains('UPDATE_REPLICATION')) {
+            options.push(actionMap.UPDATE_REPLICATION);
+          }
+          if (hMasterCustomCommands && hMasterCustomCommands.contains('STOP_REPLICATION')) {
+            options.push(actionMap.STOP_REPLICATION);
+          }
+        }
+
+
         /**
          * Display all custom commands of Master and StandBy on Service page.
          **/