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

zhangduo pushed a commit to branch branch-3
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-3 by this push:
     new e9c210d4051 HBASE-28316 Add BootstrapNodeService handlers (#5637)
e9c210d4051 is described below

commit e9c210d405193c54cd7adf07b0ab228e5faa1372
Author: Duo Zhang <zhang...@apache.org>
AuthorDate: Thu Jan 18 16:59:01 2024 +0800

    HBASE-28316 Add BootstrapNodeService handlers (#5637)
    
    Signed-off-by: Bryan Beaudreault <bbeaudrea...@apache.org>
    (cherry picked from commit c001ed3ba3c25a0d1a684c393092756b7ad9ee25)
---
 .../hbase/client/RegistryEndpointsRefresher.java   |   2 +-
 .../apache/hadoop/hbase/security/SecurityInfo.java |   6 ++
 .../org/apache/hadoop/hbase/ipc/RpcServer.java     |   7 ++
 .../hadoop/hbase/regionserver/RSRpcServices.java   |  13 ++-
 .../hadoop/hbase/security/HBasePolicyProvider.java |   7 +-
 .../hbase/client/TestBootstrapNodeUpdate.java      | 103 +++++++++++++++++++++
 ...estSecurityInfoAndHBasePolicyProviderMatch.java |  82 ++++++++++++++++
 7 files changed, 216 insertions(+), 4 deletions(-)

diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegistryEndpointsRefresher.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegistryEndpointsRefresher.java
index ac7cad27581..cdb2dd92b4f 100644
--- 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegistryEndpointsRefresher.java
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RegistryEndpointsRefresher.java
@@ -154,7 +154,7 @@ final class RegistryEndpointsRefresher {
       TimeUnit.SECONDS.toMillis(conf.getLong(initialDelaySecsConfigName, 
periodicRefreshMs / 10)));
     long minTimeBetweenRefreshesMs = TimeUnit.SECONDS
       .toMillis(conf.getLong(minIntervalSecsConfigName, 
MIN_SECS_BETWEEN_REFRESHES_DEFAULT));
-    Preconditions.checkArgument(minTimeBetweenRefreshesMs < periodicRefreshMs);
+    Preconditions.checkArgument(minTimeBetweenRefreshesMs <= 
periodicRefreshMs);
     return new RegistryEndpointsRefresher(initialDelayMs, periodicRefreshMs,
       minTimeBetweenRefreshesMs, refresher);
   }
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SecurityInfo.java 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SecurityInfo.java
index dbb4c83844a..2e16d564695 100644
--- 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SecurityInfo.java
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SecurityInfo.java
@@ -23,7 +23,9 @@ import org.apache.yetus.audience.InterfaceAudience;
 
 import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
 import 
org.apache.hadoop.hbase.shaded.protobuf.generated.AuthenticationProtos.TokenIdentifier.Kind;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.BootstrapNodeProtos;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.LockServiceProtos;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos;
 import 
org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MasterService;
 import 
org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos;
@@ -50,6 +52,10 @@ public class SecurityInfo {
       new SecurityInfo(SecurityConstants.MASTER_KRB_PRINCIPAL, 
Kind.HBASE_AUTH_TOKEN));
     infos.put(RegistryProtos.ClientMetaService.getDescriptor().getName(),
       new SecurityInfo(SecurityConstants.MASTER_KRB_PRINCIPAL, 
Kind.HBASE_AUTH_TOKEN));
+    
infos.put(BootstrapNodeProtos.BootstrapNodeService.getDescriptor().getName(),
+      new SecurityInfo(SecurityConstants.REGIONSERVER_KRB_PRINCIPAL, 
Kind.HBASE_AUTH_TOKEN));
+    infos.put(LockServiceProtos.LockService.getDescriptor().getName(),
+      new SecurityInfo(SecurityConstants.MASTER_KRB_PRINCIPAL, 
Kind.HBASE_AUTH_TOKEN));
     // NOTE: IF ADDING A NEW SERVICE, BE SURE TO UPDATE HBasePolicyProvider 
ALSO ELSE
     // new Service will not be found when all is Kerberized!!!!
   }
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java
index 6b4bf28bc95..d3ec4ff8c73 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.ipc;
 
 import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION;
 
+import com.google.errorprone.annotations.RestrictedApi;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
@@ -881,4 +882,10 @@ public abstract class RpcServer implements 
RpcServerInterface, ConfigurationObse
   protected boolean needAuthorization() {
     return authorize;
   }
+
+  @RestrictedApi(explanation = "Should only be called in tests", link = "",
+      allowedOnPath = ".*/src/test/.*")
+  public List<BlockingServiceAndInterface> getServices() {
+    return services;
+  }
 }
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
index a43fac6993e..0fe6f6476a6 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
@@ -336,8 +336,8 @@ public class RSRpcServices extends 
HBaseRpcServicesBase<HRegionServer>
 
   /**
    * Services launched in RSRpcServices. By default they are on but you can 
use the below booleans
-   * to selectively enable/disable either Admin or Client Service (Rare is the 
case where you would
-   * ever turn off one or the other).
+   * to selectively enable/disable these services (Rare is the case where you 
would ever turn off
+   * one or the other).
    */
   public static final String REGIONSERVER_ADMIN_SERVICE_CONFIG =
     "hbase.regionserver.admin.executorService";
@@ -345,6 +345,8 @@ public class RSRpcServices extends 
HBaseRpcServicesBase<HRegionServer>
     "hbase.regionserver.client.executorService";
   public static final String REGIONSERVER_CLIENT_META_SERVICE_CONFIG =
     "hbase.regionserver.client.meta.executorService";
+  public static final String REGIONSERVER_BOOTSTRAP_NODES_SERVICE_CONFIG =
+    "hbase.regionserver.bootstrap.nodes.executorService";
 
   /**
    * An Rpc callback for closing a RegionScanner.
@@ -1449,6 +1451,8 @@ public class RSRpcServices extends 
HBaseRpcServicesBase<HRegionServer>
     boolean client = 
getConfiguration().getBoolean(REGIONSERVER_CLIENT_SERVICE_CONFIG, true);
     boolean clientMeta =
       getConfiguration().getBoolean(REGIONSERVER_CLIENT_META_SERVICE_CONFIG, 
true);
+    boolean bootstrapNodes =
+      
getConfiguration().getBoolean(REGIONSERVER_BOOTSTRAP_NODES_SERVICE_CONFIG, 
true);
     List<BlockingServiceAndInterface> bssi = new ArrayList<>();
     if (client) {
       bssi.add(new 
BlockingServiceAndInterface(ClientService.newReflectiveBlockingService(this),
@@ -1462,6 +1466,11 @@ public class RSRpcServices extends 
HBaseRpcServicesBase<HRegionServer>
       bssi.add(new 
BlockingServiceAndInterface(ClientMetaService.newReflectiveBlockingService(this),
         ClientMetaService.BlockingInterface.class));
     }
+    if (bootstrapNodes) {
+      bssi.add(
+        new 
BlockingServiceAndInterface(BootstrapNodeService.newReflectiveBlockingService(this),
+          BootstrapNodeService.BlockingInterface.class));
+    }
     return new 
ImmutableList.Builder<BlockingServiceAndInterface>().addAll(bssi).build();
   }
 
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/HBasePolicyProvider.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/HBasePolicyProvider.java
index 91323a72215..30578a91909 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/HBasePolicyProvider.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/HBasePolicyProvider.java
@@ -25,7 +25,9 @@ import 
org.apache.hadoop.security.authorize.ServiceAuthorizationManager;
 import org.apache.yetus.audience.InterfaceAudience;
 
 import 
org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.AdminService;
+import 
org.apache.hadoop.hbase.shaded.protobuf.generated.BootstrapNodeProtos.BootstrapNodeService;
 import 
org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService;
+import 
org.apache.hadoop.hbase.shaded.protobuf.generated.LockServiceProtos.LockService;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos;
 import 
org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MasterService;
 import 
org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerStatusService;
@@ -44,8 +46,11 @@ public class HBasePolicyProvider extends PolicyProvider {
       new Service("security.client.protocol.acl",
         RegistryProtos.ClientMetaService.BlockingInterface.class),
       new Service("security.admin.protocol.acl", 
MasterService.BlockingInterface.class),
+      new Service("security.admin.protocol.acl", 
LockService.BlockingInterface.class),
       new Service("security.masterregion.protocol.acl",
-        RegionServerStatusService.BlockingInterface.class) };
+        RegionServerStatusService.BlockingInterface.class),
+      new Service("security.regionserver.protocol.acl",
+        BootstrapNodeService.BlockingInterface.class) };
 
   @Override
   public Service[] getServices() {
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestBootstrapNodeUpdate.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestBootstrapNodeUpdate.java
new file mode 100644
index 00000000000..d5b0ee18e59
--- /dev/null
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestBootstrapNodeUpdate.java
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+package org.apache.hadoop.hbase.client;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItem;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Set;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.HBaseRpcServicesBase;
+import org.apache.hadoop.hbase.HBaseTestingUtil;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.regionserver.BootstrapNodeManager;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
+import org.apache.hadoop.hbase.testclassification.RegionServerTests;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
+
+/**
+ * Make sure that we can update the bootstrap server from master to region 
server, and region server
+ * could also contact each other to update the bootstrap nodes.
+ */
+@Category({ RegionServerTests.class, MediumTests.class })
+public class TestBootstrapNodeUpdate {
+
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestBootstrapNodeUpdate.class);
+
+  private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
+
+  private static RpcConnectionRegistry REGISTRY;
+
+  @BeforeClass
+  public static void setUpBeforeClass() throws Exception {
+    Configuration conf = UTIL.getConfiguration();
+    conf.setLong(BootstrapNodeManager.REQUEST_MASTER_INTERVAL_SECS, 5);
+    conf.setLong(BootstrapNodeManager.REQUEST_MASTER_MIN_INTERVAL_SECS, 1);
+    conf.setLong(BootstrapNodeManager.REQUEST_REGIONSERVER_INTERVAL_SECS, 1);
+    conf.setInt(HBaseRpcServicesBase.CLIENT_BOOTSTRAP_NODE_LIMIT, 2);
+    conf.setLong(RpcConnectionRegistry.INITIAL_REFRESH_DELAY_SECS, 5);
+    conf.setLong(RpcConnectionRegistry.PERIODIC_REFRESH_INTERVAL_SECS, 1);
+    conf.setLong(RpcConnectionRegistry.MIN_SECS_BETWEEN_REFRESHES, 1);
+    UTIL.startMiniCluster(3);
+    REGISTRY = new RpcConnectionRegistry(conf);
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    Closeables.close(REGISTRY, true);
+    UTIL.shutdownMiniCluster();
+  }
+
+  @Test
+  public void testUpdate() throws Exception {
+    ServerName activeMasterServerName = REGISTRY.getActiveMaster().get();
+    ServerName masterInConf = 
ServerName.valueOf(activeMasterServerName.getHostname(),
+      activeMasterServerName.getPort(), -1);
+    // we should have master in the beginning
+    assertThat(REGISTRY.getParsedServers(), hasItem(masterInConf));
+    // and after refreshing, we will switch to use region servers
+    UTIL.waitFor(15000, () -> 
!REGISTRY.getParsedServers().contains(masterInConf)
+      && !REGISTRY.getParsedServers().contains(activeMasterServerName));
+    Set<ServerName> parsedServers = REGISTRY.getParsedServers();
+    assertEquals(2, parsedServers.size());
+    // now kill one region server
+    ServerName serverToKill = parsedServers.iterator().next();
+    UTIL.getMiniHBaseCluster().killRegionServer(serverToKill);
+    // wait until the region server disappears
+    // since the min node limit is 2, this means region server will still 
contact each other for
+    // getting bootstrap nodes, instead of requesting master directly, so this 
assert can make sure
+    // that the getAllBootstrapNodes works fine, and also the client can 
communicate with region
+    // server to update bootstrap nodes
+    UTIL.waitFor(30000, () -> 
!REGISTRY.getParsedServers().contains(serverToKill));
+    // should still have 2 servers, the remaining 2 live region servers
+    assertEquals(2, parsedServers.size());
+    // make sure the registry still works fine
+    assertNotNull(REGISTRY.getClusterId().get());
+  }
+}
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecurityInfoAndHBasePolicyProviderMatch.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecurityInfoAndHBasePolicyProviderMatch.java
new file mode 100644
index 00000000000..4a664d4d4d0
--- /dev/null
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecurityInfoAndHBasePolicyProviderMatch.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+package org.apache.hadoop.hbase.security;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItem;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.HBaseTestingUtil;
+import org.apache.hadoop.hbase.ipc.RpcServer;
+import org.apache.hadoop.hbase.ipc.RpcServer.BlockingServiceAndInterface;
+import org.apache.hadoop.hbase.ipc.RpcServerInterface;
+import org.apache.hadoop.hbase.testclassification.SecurityTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.apache.hadoop.security.authorize.Service;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Make sure that all rpc services for master and region server are properly 
configured in
+ * {@link SecurityInfo} and {@link HBasePolicyProvider}.
+ */
+@Category({ SecurityTests.class, SmallTests.class })
+public class TestSecurityInfoAndHBasePolicyProviderMatch {
+
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    
HBaseClassTestRule.forClass(TestSecurityInfoAndHBasePolicyProviderMatch.class);
+
+  private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
+
+  @BeforeClass
+  public static void setUpBeforeClass() throws Exception {
+    UTIL.startMiniCluster();
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    UTIL.shutdownMiniCluster();
+  }
+
+  private void assertServiceMatches(RpcServerInterface rpcServer) {
+    HBasePolicyProvider provider = new HBasePolicyProvider();
+    Set<Class<?>> serviceClasses =
+      
Stream.of(provider.getServices()).map(Service::getProtocol).collect(Collectors.toSet());
+    for (BlockingServiceAndInterface bsai : ((RpcServer) 
rpcServer).getServices()) {
+      assertNotNull(
+        "no security info for " + 
bsai.getBlockingService().getDescriptorForType().getName(),
+        
SecurityInfo.getInfo(bsai.getBlockingService().getDescriptorForType().getName()));
+      assertThat(serviceClasses, hasItem(bsai.getServiceInterface()));
+    }
+  }
+
+  @Test
+  public void testMatches() {
+    assertServiceMatches(
+      
UTIL.getMiniHBaseCluster().getMaster().getMasterRpcServices().getRpcServer());
+    
assertServiceMatches(UTIL.getMiniHBaseCluster().getRegionServer(0).getRpcServer());
+  }
+}

Reply via email to