You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by sm...@apache.org on 2024/03/28 14:07:59 UTC

(knox) branch master updated: KNOX-3026 - End-users can exclude certain services or roles from CM service discovery (#893)

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

smolnar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new af09c1d4e KNOX-3026 - End-users can exclude certain services or roles from CM service discovery (#893)
af09c1d4e is described below

commit af09c1d4e90941c9e545a6667af561c3b9c3a717
Author: Sandor Molnar <sm...@apache.org>
AuthorDate: Thu Mar 28 15:07:53 2024 +0100

    KNOX-3026 - End-users can exclude certain services or roles from CM service discovery (#893)
---
 .../cm/ClouderaManagerServiceDiscovery.java        | 34 +++++++++++++
 .../ClouderaManagerServiceDiscoveryMessages.java   |  3 ++
 .../cm/ClouderaManagerServiceDiscoveryTest.java    | 59 ++++++++++++++++++++--
 .../gateway/config/impl/GatewayConfigImpl.java     | 12 +++++
 .../org/apache/knox/gateway/GatewayTestConfig.java | 10 ++++
 .../apache/knox/gateway/config/GatewayConfig.java  | 12 +++++
 6 files changed, 125 insertions(+), 5 deletions(-)

diff --git a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscovery.java b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscovery.java
index 8d1227a56..532dcec04 100644
--- a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscovery.java
+++ b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscovery.java
@@ -52,6 +52,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
 
 
 /**
@@ -92,6 +93,8 @@ public class ClouderaManagerServiceDiscovery implements ServiceDiscovery, Cluste
   private final AtomicInteger retryAttempts = new AtomicInteger(0);
   private final int retrySleepSeconds = 3;  // It's been agreed that we not expose this config
   private int maxRetryAttempts = -1;
+  private Collection<String> excludedServiceTypes = Collections.emptySet();
+  private Collection<String> excludedRoleTypes = Collections.emptySet();
 
   ClouderaManagerServiceDiscovery(GatewayConfig gatewayConfig) {
     this(false, gatewayConfig);
@@ -116,9 +119,15 @@ public class ClouderaManagerServiceDiscovery implements ServiceDiscovery, Cluste
     if (gatewayConfig != null) {
       repository.setCacheEntryTTL(gatewayConfig.getClouderaManagerServiceDiscoveryRepositoryEntryTTL());
       configureRetryParams(gatewayConfig);
+      excludedServiceTypes = getLowercaseStringCollection(gatewayConfig.getClouderaManagerServiceDiscoveryExcludedServiceTypes());
+      excludedRoleTypes = getLowercaseStringCollection(gatewayConfig.getClouderaManagerServiceDiscoveryExcludedRoleTypes());
     }
   }
 
+  private Collection<String> getLowercaseStringCollection(Collection<String> original) {
+    return original == null ? Collections.emptySet() : original.stream().map(serviceType -> serviceType.toLowerCase(Locale.ROOT)).collect(Collectors.toSet());
+  }
+
   private void configureRetryParams(GatewayConfig gatewayConfig) {
     final int configuredMaxRetryAttempts = gatewayConfig.getClouderaManagerServiceDiscoveryMaximumRetryAttempts();
     if (configuredMaxRetryAttempts > 0) {
@@ -356,6 +365,14 @@ public class ClouderaManagerServiceDiscovery implements ServiceDiscovery, Cluste
         final ApiServiceList serviceList = servicesResourceApi.readServices(serviceDiscoveryConfig.getCluster(), VIEW_SUMMARY);
         services = serviceList == null ? new ArrayList<>() : serviceList.getItems();
 
+        services = services.stream().filter(service -> {
+          if (excludedServiceTypes.contains(service.getType().toLowerCase(Locale.ROOT))) {
+            log.skipServiceDiscovery(service.getName(), service.getType());
+            return false;
+          }
+          return true;
+        }).collect(Collectors.toList());
+
         // make sure that services are populated in the repository
         services.forEach(service -> repository.addService(serviceDiscoveryConfig, service));
       } catch (ApiException e) {
@@ -409,6 +426,8 @@ public class ClouderaManagerServiceDiscovery implements ServiceDiscovery, Cluste
           log.noRoles();
         }
 
+        roles = excludeRoles(roles);
+
         // make sure that role is populated in the service discovery repository to avoid subsequent CM calls
         if (roles != null && roles.getItems() != null) {
           repository.addRoles(serviceDiscoveryConfig, service, roles);
@@ -422,6 +441,21 @@ public class ClouderaManagerServiceDiscovery implements ServiceDiscovery, Cluste
     return roles;
   }
 
+  private ApiRoleList excludeRoles(ApiRoleList roles) {
+    if (roles == null || roles.getItems() == null) {
+      return roles;
+    }
+    final ApiRoleList filteredRoles = new ApiRoleList();
+    roles.getItems().forEach(role -> {
+      if (excludedRoleTypes.contains(role.getType().toLowerCase(Locale.ROOT))) {
+        log.skipRoleDiscovery(role.getName(), role.getType());
+      } else {
+        filteredRoles.addItemsItem(role);
+      }
+    });
+    return filteredRoles;
+  }
+
   private ApiConfigList getRoleConfig(ServiceDiscoveryConfig serviceDiscoveryConfig, RolesResourceApi rolesResourceApi, ApiService service, ApiRole role) throws ApiException {
     log.lookupRoleConfigsFromRepository();
     // first, try in the service discovery repository
diff --git a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryMessages.java b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryMessages.java
index fd77c3552..285c09b68 100644
--- a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryMessages.java
+++ b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryMessages.java
@@ -48,6 +48,9 @@ public interface ClouderaManagerServiceDiscoveryMessages {
   @Message(level = MessageLevel.INFO, text = "Discovering service role: {0} ({1}) ...")
   void discoveringServiceRole(String roleName, String roleType);
 
+  @Message(level = MessageLevel.INFO, text = "Skipping role discovery: {0} ({1})")
+  void skipRoleDiscovery(String roleName, String roleType);
+
   @Message(level = MessageLevel.INFO, text = "Discovered service role: {0} ({1})")
   void discoveredServiceRole(String roleName, String roleType);
 
diff --git a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
index 76843e11f..9d98643ba 100644
--- a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
+++ b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
@@ -64,6 +64,7 @@ import org.junit.Test;
 import java.lang.reflect.Type;
 import java.net.SocketTimeoutException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -402,7 +403,26 @@ public class ClouderaManagerServiceDiscoveryTest {
   }
 
   @Test
-  public void testWebHCatDiscovery() {
+  public void testIncludeHiveServiceIncludeWebHCatDiscovery() {
+    testWebHCatDiscovery(true, true);
+  }
+
+  @Test
+  public void testExcludeHiveServiceIncludeWebHCatDiscovery() {
+    testWebHCatDiscovery(false, true);
+  }
+
+  @Test
+  public void testIncludeHiveServiceExcludeWebHCatDiscovery() {
+    testWebHCatDiscovery(true, false);
+  }
+
+  @Test
+  public void testExcludeHiveServiceExcludeWebHCatDiscovery() {
+    testWebHCatDiscovery(false, false);
+  }
+
+  private void testWebHCatDiscovery(boolean excludeHiveService, boolean excludeWebHCatRole) {
     final String hostName = "webhcat-host";
     final String port     = "22222";
     final String expectedURL = "http://" + hostName + ":" + port + "/templeton";
@@ -417,12 +437,18 @@ public class ClouderaManagerServiceDiscoveryTest {
                                                        "HIVE-1-WEBHCAT-1",
                                                        WebHCatServiceModelGenerator.ROLE_TYPE,
                                                        Collections.emptyMap(),
-                                                       roleProperties);
+                                                       roleProperties,
+                                                       false,
+                                                       excludeHiveService ? WebHCatServiceModelGenerator.SERVICE_TYPE : null,
+                                                       excludeWebHCatRole ?  WebHCatServiceModelGenerator.ROLE_TYPE : null);
 
     List<String> urls = cluster.getServiceURLs("WEBHCAT");
     assertNotNull(urls);
-    assertEquals(1, urls.size());
-    assertEquals(expectedURL, urls.get(0));
+    final boolean expectExclusion = excludeHiveService || excludeWebHCatRole;
+    assertEquals(expectExclusion ? 0 : 1, urls.size());
+    if (!expectExclusion) {
+      assertEquals(expectedURL, urls.get(0));
+    }
   }
 
   @Test
@@ -1168,6 +1194,17 @@ public class ClouderaManagerServiceDiscoveryTest {
     return doTestDiscovery(hostName, serviceName, serviceType, roleName, roleType, serviceProperties, roleProperties, false);
   }
 
+  private ServiceDiscovery.Cluster doTestDiscovery(final String hostName,
+      final String serviceName,
+      final String serviceType,
+      final String roleName,
+      final String roleType,
+      final Map<String, String> serviceProperties,
+      final Map<String, String> roleProperties,
+      boolean testRetry) {
+    return doTestDiscovery(hostName, serviceName, serviceType, roleName, roleType, serviceProperties, roleProperties, testRetry, null, null);
+  }
+
   private ServiceDiscovery.Cluster doTestDiscovery(final String hostName,
                                                    final String serviceName,
                                                    final String serviceType,
@@ -1175,7 +1212,9 @@ public class ClouderaManagerServiceDiscoveryTest {
                                                    final String roleType,
                                                    final Map<String, String> serviceProperties,
                                                    final Map<String, String> roleProperties,
-                                                   boolean testRetry) {
+                                                   boolean testRetry,
+                                                   String excludedServiceType,
+                                                   String excludedRoleType) {
     final String clusterName = "cluster-1";
 
     GatewayConfig gwConf = EasyMock.createNiceMock(GatewayConfig.class);
@@ -1185,6 +1224,16 @@ public class ClouderaManagerServiceDiscoveryTest {
     }
     EasyMock.expect(gwConf.getIncludedSSLCiphers()).andReturn(Collections.emptyList()).anyTimes();
     EasyMock.expect(gwConf.getIncludedSSLProtocols()).andReturn(Collections.emptySet()).anyTimes();
+    if (excludedServiceType == null) {
+      EasyMock.expect(gwConf.getClouderaManagerServiceDiscoveryExcludedServiceTypes()).andReturn(Collections.emptySet()).anyTimes();
+    } else {
+      EasyMock.expect(gwConf.getClouderaManagerServiceDiscoveryExcludedServiceTypes()).andReturn(Arrays.asList(excludedServiceType)).anyTimes();
+    }
+    if (excludedRoleType == null) {
+      EasyMock.expect(gwConf.getClouderaManagerServiceDiscoveryExcludedRoleTypes()).andReturn(Collections.emptySet()).anyTimes();
+    } else {
+      EasyMock.expect(gwConf.getClouderaManagerServiceDiscoveryExcludedRoleTypes()).andReturn(Arrays.asList(excludedRoleType)).anyTimes();
+    }
     EasyMock.replay(gwConf);
 
     ServiceDiscoveryConfig sdConfig = createMockDiscoveryConfig(clusterName);
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index 01858a597..1b6e967a7 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -297,6 +297,8 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
   private static final String CLOUDERA_MANAGER_SERVICE_DISCOVERY_CONNECT_TIMEOUT = GATEWAY_CONFIG_FILE_PREFIX + ".cloudera.manager.service.discovery.connect.timeout.ms";
   private static final String CLOUDERA_MANAGER_SERVICE_DISCOVERY_READ_TIMEOUT = GATEWAY_CONFIG_FILE_PREFIX + ".cloudera.manager.service.discovery.read.timeout.ms";
   private static final String CLOUDERA_MANAGER_SERVICE_DISCOVERY_WRITE_TIMEOUT = GATEWAY_CONFIG_FILE_PREFIX + ".cloudera.manager.service.discovery.write.timeout.ms";
+  private static final String CLOUDERA_MANAGER_SERVICE_DISCOVERY_EXCLUDED_SERVICE_TYPES = GATEWAY_CONFIG_FILE_PREFIX + ".cloudera.manager.service.discovery.excluded.service.types";
+  private static final String CLOUDERA_MANAGER_SERVICE_DISCOVERY_EXCLUDED_ROLE_TYPES = GATEWAY_CONFIG_FILE_PREFIX + ".cloudera.manager.service.discovery.excluded.role.types";
 
   private static final long CLOUDERA_MANAGER_SERVICE_DISCOVERY_CONNECT_TIMEOUT_DEFAULT = 10000;
   private static final long CLOUDERA_MANAGER_SERVICE_DISCOVERY_READ_TIMEOUT_DEFAULT = 10000;
@@ -1301,6 +1303,16 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
     return getInt(CLOUDERA_MANAGER_SERVICE_DISCOVERY_MAX_RETRY_ATTEMPS, DEFAULT_CM_SERVICE_DISCOVERY_MAX_RETRY_ATTEMPTS);
   }
 
+  @Override
+  public Collection<String> getClouderaManagerServiceDiscoveryExcludedServiceTypes() {
+    return getTrimmedStringCollection(CLOUDERA_MANAGER_SERVICE_DISCOVERY_EXCLUDED_SERVICE_TYPES);
+  }
+
+  @Override
+  public Collection<String> getClouderaManagerServiceDiscoveryExcludedRoleTypes() {
+    return getTrimmedStringCollection(CLOUDERA_MANAGER_SERVICE_DISCOVERY_EXCLUDED_ROLE_TYPES);
+  }
+
   @Override
   public boolean isServerManagedTokenStateEnabled() {
     return getBoolean(TOKEN_STATE_SERVER_MANAGED, false);
diff --git a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
index b179b0a9c..e3f2ddab5 100644
--- a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
+++ b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
@@ -871,6 +871,16 @@ public class GatewayTestConfig extends Configuration implements GatewayConfig {
     return -1;
   }
 
+  @Override
+  public Collection<String> getClouderaManagerServiceDiscoveryExcludedServiceTypes() {
+    return Collections.emptySet();
+  }
+
+  @Override
+  public Collection<String> getClouderaManagerServiceDiscoveryExcludedRoleTypes() {
+    return Collections.emptySet();
+  }
+
   @Override
   public boolean isServerManagedTokenStateEnabled() {
     return false;
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
index c2cbc3692..352aabbe5 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
@@ -750,6 +750,18 @@ public interface GatewayConfig {
    */
   int getClouderaManagerServiceDiscoveryMaximumRetryAttempts();
 
+  /**
+   * @return a collection of comma separated service types that should be excluded
+   *         from CM service discovery (e.g. HDFS, KNOX, RANGER, HIVE, etc...)
+   */
+  Collection<String> getClouderaManagerServiceDiscoveryExcludedServiceTypes();
+
+  /**
+   * @return a collection of comma separated role types that should be excluded
+   *         from CM service discovery (e.g. KNOX_GATEWAY, IDBROKER, DATANODE, HIVEMETASTORE, etc...)
+   */
+  Collection<String> getClouderaManagerServiceDiscoveryExcludedRoleTypes();
+
   /**
    * @return true, if state for tokens issued by the Knox Token service should be managed by Knox.
    */