View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase;
20  
21  import java.io.IOException;
22  
23  import javax.management.remote.JMXConnector;
24  import javax.management.remote.JMXConnectorFactory;
25  import javax.naming.ServiceUnavailableException;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.conf.Configuration;
30  import org.apache.hadoop.hbase.client.Admin;
31  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
32  import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
33  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
34  import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
35  import org.apache.hadoop.hbase.security.AccessDeniedException;
36  import org.apache.hadoop.hbase.security.access.AccessController;
37  import org.apache.hadoop.hbase.testclassification.MediumTests;
38  import org.apache.hadoop.hbase.testclassification.MiscTests;
39  import org.junit.After;
40  import org.junit.Assert;
41  import org.junit.Before;
42  import org.junit.Test;
43  import org.junit.experimental.categories.Category;
44  
45  /**
46   * Test case for JMX Connector Server.
47   */
48  @Category({ MiscTests.class, MediumTests.class })
49  public class TestJMXConnectorServer {
50    private static final Log LOG = LogFactory.getLog(TestJMXConnectorServer.class);
51    private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
52  
53    private static Configuration conf = null;
54    private static Admin admin;
55    // RMI registry port
56    private static int rmiRegistryPort = 61120;
57    // Switch for customized Accesscontroller to throw ACD exception while executing test case
58    static boolean hasAccess;
59  
60    @Before
61    public void setUp() throws Exception {
62      UTIL = new HBaseTestingUtility();
63      conf = UTIL.getConfiguration();
64    }
65  
66    @After
67    public void tearDown() throws Exception {
68      // Set to true while stopping cluster
69      hasAccess = true;
70      admin.close();
71      UTIL.shutdownMiniCluster();
72    }
73  
74    /**
75     * This tests to validate the HMaster's ConnectorServer after unauthorised stopMaster call.
76     */
77    @Test(timeout = 180000)
78    public void testHMConnectorServerWhenStopMaster() throws Exception {
79      conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
80        JMXListener.class.getName() + "," + MyAccessController.class.getName());
81      conf.setInt("master.rmi.registry.port", rmiRegistryPort);
82      UTIL.startMiniCluster();
83      admin = UTIL.getConnection().getAdmin();
84  
85      // try to stop master
86      boolean accessDenied = false;
87      try {
88        hasAccess = false;
89        LOG.info("Stopping HMaster...");
90        admin.stopMaster();
91      } catch (AccessDeniedException e) {
92        LOG.info("Exception occured while stopping HMaster. ", e);
93        accessDenied = true;
94      }
95      Assert.assertTrue(accessDenied);
96  
97      // Check whether HMaster JMX Connector server can be connected
98      JMXConnector connector = null;
99      try {
100       connector = JMXConnectorFactory
101           .connect(JMXListener.buildJMXServiceURL(rmiRegistryPort, rmiRegistryPort));
102     } catch (IOException e) {
103       if (e.getCause() instanceof ServiceUnavailableException) {
104         Assert.fail("Can't connect to HMaster ConnectorServer.");
105       }
106     }
107     Assert.assertNotNull("JMXConnector should not be null.", connector);
108     connector.close();
109   }
110 
111   /**
112    * This tests to validate the RegionServer's ConnectorServer after unauthorised stopRegionServer
113    * call.
114    */
115   @Test(timeout = 180000)
116   public void testRSConnectorServerWhenStopRegionServer() throws Exception {
117     conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY,
118       JMXListener.class.getName() + "," + MyAccessController.class.getName());
119     conf.setInt("regionserver.rmi.registry.port", rmiRegistryPort);
120     UTIL.startMiniCluster();
121     admin = UTIL.getConnection().getAdmin();
122 
123     hasAccess = false;
124     ServerName serverName = UTIL.getHBaseCluster().getRegionServer(0).getServerName();
125     LOG.info("Stopping Region Server...");
126     admin.stopRegionServer(serverName.getHostname() + ":" + serverName.getPort());
127 
128     // Check whether Region Sever JMX Connector server can be connected
129     JMXConnector connector = null;
130     try {
131       connector = JMXConnectorFactory
132           .connect(JMXListener.buildJMXServiceURL(rmiRegistryPort, rmiRegistryPort));
133     } catch (IOException e) {
134       if (e.getCause() instanceof ServiceUnavailableException) {
135         Assert.fail("Can't connect to Region Server ConnectorServer.");
136       }
137     }
138     Assert.assertNotNull("JMXConnector should not be null.", connector);
139     connector.close();
140   }
141 
142   /**
143    * This tests to validate the HMaster's ConnectorServer after unauthorised shutdown call.
144    */
145   @Test(timeout = 180000)
146   public void testHMConnectorServerWhenShutdownCluster() throws Exception {
147     conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
148       JMXListener.class.getName() + "," + MyAccessController.class.getName());
149     conf.setInt("master.rmi.registry.port", rmiRegistryPort);
150 
151     UTIL.startMiniCluster();
152     admin = UTIL.getConnection().getAdmin();
153 
154     boolean accessDenied = false;
155     try {
156       hasAccess = false;
157       LOG.info("Stopping HMaster...");
158       admin.shutdown();
159     } catch (AccessDeniedException e) {
160       LOG.error("Exception occured while stopping HMaster. ", e);
161       accessDenied = true;
162     }
163     Assert.assertTrue(accessDenied);
164 
165     // Check whether HMaster JMX Connector server can be connected
166     JMXConnector connector = null;
167     try {
168       connector = JMXConnectorFactory
169           .connect(JMXListener.buildJMXServiceURL(rmiRegistryPort, rmiRegistryPort));
170     } catch (IOException e) {
171       if (e.getCause() instanceof ServiceUnavailableException) {
172         Assert.fail("Can't connect to HMaster ConnectorServer.");
173       }
174     }
175     Assert.assertNotNull("JMXConnector should not be null.", connector);
176     connector.close();
177   }
178 
179   /*
180    * Customized class for test case execution which will throw ACD exception while executing
181    * stopMaster/preStopRegionServer/preShutdown explicitly.
182    */
183   public static class MyAccessController extends AccessController {
184     @Override
185     public void preStopMaster(ObserverContext<MasterCoprocessorEnvironment> c) throws IOException {
186       if (!hasAccess) {
187         throw new AccessDeniedException("Insufficient permissions to stop master");
188       }
189     }
190 
191     @Override
192     public void preStopRegionServer(ObserverContext<RegionServerCoprocessorEnvironment> ctx)
193         throws IOException {
194       if (!hasAccess) {
195         throw new AccessDeniedException("Insufficient permissions to stop region server.");
196       }
197     }
198 
199     @Override
200     public void preShutdown(ObserverContext<MasterCoprocessorEnvironment> c) throws IOException {
201       if (!hasAccess) {
202         throw new AccessDeniedException("Insufficient permissions to shut down cluster.");
203       }
204     }
205   }
206 }