001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase; 019 020import java.io.IOException; 021import javax.management.remote.JMXConnector; 022import javax.management.remote.JMXConnectorFactory; 023import javax.naming.ServiceUnavailableException; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.hbase.client.Admin; 026import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 027import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; 028import org.apache.hadoop.hbase.coprocessor.ObserverContext; 029import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment; 030import org.apache.hadoop.hbase.security.AccessDeniedException; 031import org.apache.hadoop.hbase.security.access.AccessController; 032import org.apache.hadoop.hbase.testclassification.MediumTests; 033import org.apache.hadoop.hbase.testclassification.MiscTests; 034import org.junit.After; 035import org.junit.AfterClass; 036import org.junit.Assert; 037import org.junit.Before; 038import org.junit.BeforeClass; 039import org.junit.ClassRule; 040import org.junit.Test; 041import org.junit.experimental.categories.Category; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045/** 046 * Test case for JMX Connector Server. 047 */ 048@Category({ MiscTests.class, MediumTests.class }) 049public class TestJMXConnectorServer { 050 051 @ClassRule 052 public static final HBaseClassTestRule CLASS_RULE = 053 HBaseClassTestRule.forClass(TestJMXConnectorServer.class); 054 055 private static final Logger LOG = LoggerFactory.getLogger(TestJMXConnectorServer.class); 056 private static HBaseTestingUtil UTIL = new HBaseTestingUtil(); 057 058 private static Configuration conf = null; 059 private static Admin admin; 060 // RMI registry port 061 private static int rmiRegistryPort; 062 // Switch for customized Accesscontroller to throw ACD exception while executing test case 063 private volatile static boolean hasAccess; 064 065 @BeforeClass 066 public static void setUpBeforeClass() throws Exception { 067 conf = UTIL.getConfiguration(); 068 String cps = JMXListener.class.getName() + "," + MyAccessController.class.getName(); 069 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, cps); 070 conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, cps); 071 rmiRegistryPort = UTIL.randomFreePort(); 072 conf.setInt("master.rmi.registry.port", rmiRegistryPort); 073 conf.setInt("regionserver.rmi.registry.port", rmiRegistryPort); 074 UTIL.startMiniCluster(); 075 admin = UTIL.getConnection().getAdmin(); 076 } 077 078 @AfterClass 079 public static void tearDownAfterClass() throws Exception { 080 admin.close(); 081 UTIL.shutdownMiniCluster(); 082 } 083 084 @Before 085 public void setUp() { 086 hasAccess = false; 087 } 088 089 @After 090 public void tearDown() { 091 hasAccess = true; 092 } 093 094 /** 095 * This tests to validate the HMaster's ConnectorServer after unauthorised stopMaster call. 096 */ 097 @Test 098 public void testHMConnectorServerWhenStopMaster() throws Exception { 099 // try to stop master 100 boolean accessDenied = false; 101 try { 102 LOG.info("Stopping HMaster..."); 103 admin.stopMaster(); 104 } catch (AccessDeniedException e) { 105 LOG.info("Exception occurred while stopping HMaster. ", e); 106 accessDenied = true; 107 } 108 Assert.assertTrue(accessDenied); 109 110 checkConnector(); 111 } 112 113 /** 114 * This tests to validate the RegionServer's ConnectorServer after unauthorised stopRegionServer 115 * call. 116 */ 117 @Test 118 public void testRSConnectorServerWhenStopRegionServer() throws Exception { 119 ServerName serverName = UTIL.getHBaseCluster().getRegionServer(0).getServerName(); 120 LOG.info("Stopping Region Server..."); 121 admin.stopRegionServer(serverName.getHostname() + ":" + serverName.getPort()); 122 123 checkConnector(); 124 } 125 126 /** 127 * This tests to validate the HMaster's ConnectorServer after unauthorised shutdown call. 128 */ 129 @Test 130 public void testHMConnectorServerWhenShutdownCluster() throws Exception { 131 boolean accessDenied = false; 132 try { 133 LOG.info("Stopping HMaster..."); 134 admin.shutdown(); 135 } catch (AccessDeniedException e) { 136 LOG.error("Exception occurred while stopping HMaster. ", e); 137 accessDenied = true; 138 } 139 Assert.assertTrue(accessDenied); 140 141 checkConnector(); 142 } 143 144 private void checkConnector() throws Exception { 145 // Check whether HMaster JMX Connector server can be connected 146 JMXConnector connector = null; 147 try { 148 connector = JMXConnectorFactory 149 .connect(JMXListener.buildJMXServiceURL(rmiRegistryPort, rmiRegistryPort)); 150 } catch (IOException e) { 151 if (e.getCause() instanceof ServiceUnavailableException) { 152 Assert.fail("Can't connect to ConnectorServer."); 153 } 154 } 155 Assert.assertNotNull("JMXConnector should not be null.", connector); 156 connector.close(); 157 } 158 159 /* 160 * Customized class for test case execution which will throw ACD exception while executing 161 * stopMaster/preStopRegionServer/preShutdown explicitly. 162 */ 163 public static class MyAccessController extends AccessController { 164 @Override 165 public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx) { 166 // Do nothing. In particular, stop the creation of the hbase:acl table. It makes the 167 // shutdown take time. 168 } 169 170 @Override 171 public void preStopMaster(ObserverContext<MasterCoprocessorEnvironment> c) throws IOException { 172 if (!hasAccess) { 173 throw new AccessDeniedException("Insufficient permissions to stop master"); 174 } 175 } 176 177 @Override 178 public void preStopRegionServer(ObserverContext<RegionServerCoprocessorEnvironment> ctx) 179 throws IOException { 180 if (!hasAccess) { 181 throw new AccessDeniedException("Insufficient permissions to stop region server."); 182 } 183 } 184 185 @Override 186 public void preShutdown(ObserverContext<MasterCoprocessorEnvironment> c) throws IOException { 187 if (!hasAccess) { 188 throw new AccessDeniedException("Insufficient permissions to shut down cluster."); 189 } 190 } 191 192 @Override 193 public void preExecuteProcedures(ObserverContext<RegionServerCoprocessorEnvironment> ctx) 194 throws IOException { 195 // FIXME: ignore the procedure permission check since in our UT framework master is neither 196 // the systemuser nor the superuser so we can not call executeProcedures... 197 } 198 } 199}