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.client;
019
020import static org.hamcrest.MatcherAssert.assertThat;
021import static org.hamcrest.Matchers.hasItem;
022import static org.junit.jupiter.api.Assertions.assertEquals;
023import static org.junit.jupiter.api.Assertions.assertNotNull;
024
025import java.util.Set;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.HBaseRpcServicesBase;
028import org.apache.hadoop.hbase.HBaseTestingUtil;
029import org.apache.hadoop.hbase.ServerName;
030import org.apache.hadoop.hbase.regionserver.BootstrapNodeManager;
031import org.apache.hadoop.hbase.security.UserProvider;
032import org.apache.hadoop.hbase.testclassification.MediumTests;
033import org.apache.hadoop.hbase.testclassification.RegionServerTests;
034import org.junit.jupiter.api.AfterAll;
035import org.junit.jupiter.api.BeforeAll;
036import org.junit.jupiter.api.Tag;
037import org.junit.jupiter.api.Test;
038
039import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
040
041/**
042 * Make sure that we can update the bootstrap server from master to region server, and region server
043 * could also contact each other to update the bootstrap nodes.
044 */
045@Tag(RegionServerTests.TAG)
046@Tag(MediumTests.TAG)
047public class TestBootstrapNodeUpdate {
048
049  private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
050
051  private static RpcConnectionRegistry REGISTRY;
052
053  @BeforeAll
054  public static void setUpBeforeClass() throws Exception {
055    Configuration conf = UTIL.getConfiguration();
056    conf.setLong(BootstrapNodeManager.REQUEST_MASTER_INTERVAL_SECS, 5);
057    conf.setLong(BootstrapNodeManager.REQUEST_MASTER_MIN_INTERVAL_SECS, 1);
058    conf.setLong(BootstrapNodeManager.REQUEST_REGIONSERVER_INTERVAL_SECS, 1);
059    conf.setInt(HBaseRpcServicesBase.CLIENT_BOOTSTRAP_NODE_LIMIT, 2);
060    conf.setLong(RpcConnectionRegistry.INITIAL_REFRESH_DELAY_SECS, 5);
061    conf.setLong(RpcConnectionRegistry.PERIODIC_REFRESH_INTERVAL_SECS, 1);
062    conf.setLong(RpcConnectionRegistry.MIN_SECS_BETWEEN_REFRESHES, 1);
063    UTIL.startMiniCluster(3);
064    REGISTRY = new RpcConnectionRegistry(conf, UserProvider.instantiate(conf).getCurrent());
065  }
066
067  @AfterAll
068  public static void tearDownAfterClass() throws Exception {
069    Closeables.close(REGISTRY, true);
070    UTIL.shutdownMiniCluster();
071  }
072
073  @Test
074  public void testUpdate() throws Exception {
075    ServerName activeMasterServerName = REGISTRY.getActiveMaster().get();
076    ServerName masterInConf = ServerName.valueOf(activeMasterServerName.getHostname(),
077      activeMasterServerName.getPort(), -1);
078    // we should have master in the beginning
079    assertThat(REGISTRY.getParsedServers(), hasItem(masterInConf));
080    // and after refreshing, we will switch to use region servers
081    UTIL.waitFor(15000, () -> !REGISTRY.getParsedServers().contains(masterInConf)
082      && !REGISTRY.getParsedServers().contains(activeMasterServerName));
083    Set<ServerName> parsedServers = REGISTRY.getParsedServers();
084    assertEquals(2, parsedServers.size());
085    // now kill one region server
086    ServerName serverToKill = parsedServers.iterator().next();
087    UTIL.getMiniHBaseCluster().killRegionServer(serverToKill);
088    // wait until the region server disappears
089    // since the min node limit is 2, this means region server will still contact each other for
090    // getting bootstrap nodes, instead of requesting master directly, so this assert can make sure
091    // that the getAllBootstrapNodes works fine, and also the client can communicate with region
092    // server to update bootstrap nodes
093    UTIL.waitFor(30000, () -> !REGISTRY.getParsedServers().contains(serverToKill));
094    // should still have 2 servers, the remaining 2 live region servers
095    assertEquals(2, parsedServers.size());
096    // make sure the registry still works fine
097    assertNotNull(REGISTRY.getClusterId().get());
098  }
099}