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.jupiter.api.AfterAll; 035import org.junit.jupiter.api.AfterEach; 036import org.junit.jupiter.api.Assertions; 037import org.junit.jupiter.api.BeforeAll; 038import org.junit.jupiter.api.BeforeEach; 039import org.junit.jupiter.api.Tag; 040import org.junit.jupiter.api.Test; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044/** 045 * Test case for JMX Connector Server. 046 */ 047@Tag(MiscTests.TAG) 048@Tag(MediumTests.TAG) 049public class TestJMXConnectorServer { 050 051 private static final Logger LOG = LoggerFactory.getLogger(TestJMXConnectorServer.class); 052 private static HBaseTestingUtil UTIL = new HBaseTestingUtil(); 053 054 private static Configuration conf = null; 055 private static Admin admin; 056 // RMI registry port 057 private static int rmiRegistryPort; 058 // Switch for customized Accesscontroller to throw ACD exception while executing test case 059 private volatile static boolean hasAccess; 060 061 @BeforeAll 062 public static void setUpBeforeClass() throws Exception { 063 conf = UTIL.getConfiguration(); 064 String cps = JMXListener.class.getName() + "," + MyAccessController.class.getName(); 065 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, cps); 066 conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, cps); 067 rmiRegistryPort = UTIL.randomFreePort(); 068 conf.setInt("master.rmi.registry.port", rmiRegistryPort); 069 conf.setInt("regionserver.rmi.registry.port", rmiRegistryPort); 070 UTIL.startMiniCluster(); 071 admin = UTIL.getConnection().getAdmin(); 072 } 073 074 @AfterAll 075 public static void tearDownAfterClass() throws Exception { 076 admin.close(); 077 UTIL.shutdownMiniCluster(); 078 } 079 080 @BeforeEach 081 public void setUp() { 082 hasAccess = false; 083 } 084 085 @AfterEach 086 public void tearDown() { 087 hasAccess = true; 088 } 089 090 /** 091 * This tests to validate the HMaster's ConnectorServer after unauthorised stopMaster call. 092 */ 093 @Test 094 public void testHMConnectorServerWhenStopMaster() throws Exception { 095 // try to stop master 096 boolean accessDenied = false; 097 try { 098 LOG.info("Stopping HMaster..."); 099 admin.stopMaster(); 100 } catch (AccessDeniedException e) { 101 LOG.info("Exception occurred while stopping HMaster. ", e); 102 accessDenied = true; 103 } 104 Assertions.assertTrue(accessDenied); 105 106 checkConnector(); 107 } 108 109 /** 110 * This tests to validate the RegionServer's ConnectorServer after unauthorised stopRegionServer 111 * call. 112 */ 113 @Test 114 public void testRSConnectorServerWhenStopRegionServer() throws Exception { 115 ServerName serverName = UTIL.getHBaseCluster().getRegionServer(0).getServerName(); 116 LOG.info("Stopping Region Server..."); 117 admin.stopRegionServer(serverName.getHostname() + ":" + serverName.getPort()); 118 119 checkConnector(); 120 } 121 122 /** 123 * This tests to validate the HMaster's ConnectorServer after unauthorised shutdown call. 124 */ 125 @Test 126 public void testHMConnectorServerWhenShutdownCluster() throws Exception { 127 boolean accessDenied = false; 128 try { 129 LOG.info("Stopping HMaster..."); 130 admin.shutdown(); 131 } catch (AccessDeniedException e) { 132 LOG.error("Exception occurred while stopping HMaster. ", e); 133 accessDenied = true; 134 } 135 Assertions.assertTrue(accessDenied); 136 137 checkConnector(); 138 } 139 140 private void checkConnector() throws Exception { 141 // Check whether HMaster JMX Connector server can be connected 142 JMXConnector connector = null; 143 try { 144 connector = JMXConnectorFactory 145 .connect(JMXListener.buildJMXServiceURL(rmiRegistryPort, rmiRegistryPort)); 146 } catch (IOException e) { 147 if (e.getCause() instanceof ServiceUnavailableException) { 148 Assertions.fail("Can't connect to ConnectorServer."); 149 } 150 } 151 Assertions.assertNotNull(connector, "JMXConnector should not be null."); 152 connector.close(); 153 } 154 155 /* 156 * Customized class for test case execution which will throw ACD exception while executing 157 * stopMaster/preStopRegionServer/preShutdown explicitly. 158 */ 159 public static class MyAccessController extends AccessController { 160 @Override 161 public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx) { 162 // Do nothing. In particular, stop the creation of the hbase:acl table. It makes the 163 // shutdown take time. 164 } 165 166 @Override 167 public void preStopMaster(ObserverContext<MasterCoprocessorEnvironment> c) throws IOException { 168 if (!hasAccess) { 169 throw new AccessDeniedException("Insufficient permissions to stop master"); 170 } 171 } 172 173 @Override 174 public void preStopRegionServer(ObserverContext<RegionServerCoprocessorEnvironment> ctx) 175 throws IOException { 176 if (!hasAccess) { 177 throw new AccessDeniedException("Insufficient permissions to stop region server."); 178 } 179 } 180 181 @Override 182 public void preShutdown(ObserverContext<MasterCoprocessorEnvironment> c) throws IOException { 183 if (!hasAccess) { 184 throw new AccessDeniedException("Insufficient permissions to shut down cluster."); 185 } 186 } 187 188 @Override 189 public void preExecuteProcedures(ObserverContext<RegionServerCoprocessorEnvironment> ctx) 190 throws IOException { 191 // FIXME: ignore the procedure permission check since in our UT framework master is neither 192 // the systemuser nor the superuser so we can not call executeProcedures... 193 } 194 } 195}