|
35 | 35 | import static org.testng.Assert.assertThrows; |
36 | 36 | import static org.testng.Assert.assertTrue; |
37 | 37 | import static org.testng.Assert.fail; |
| 38 | +import com.google.common.collect.Sets; |
38 | 39 | import java.lang.reflect.Field; |
39 | 40 | import java.net.URI; |
40 | 41 | import java.net.URL; |
|
105 | 106 | import org.apache.pulsar.common.policies.data.BookieAffinityGroupData; |
106 | 107 | import org.apache.pulsar.common.policies.data.BundlesData; |
107 | 108 | import org.apache.pulsar.common.policies.data.ClusterData; |
| 109 | +import org.apache.pulsar.common.policies.data.ClusterDataImpl; |
108 | 110 | import org.apache.pulsar.common.policies.data.DispatchRate; |
109 | 111 | import org.apache.pulsar.common.policies.data.OffloadPoliciesImpl; |
110 | 112 | import org.apache.pulsar.common.policies.data.PersistencePolicies; |
@@ -2280,4 +2282,122 @@ public void testMigratedInfoIsNotLostDuringOtherLocalPoliciesUpdate() throws Exc |
2280 | 2282 | admin.namespaces().deleteNamespaceAntiAffinityGroup(namespace); |
2281 | 2283 | assertTrue(admin.namespaces().getPolicies(namespace).migrated); |
2282 | 2284 | } |
| 2285 | + |
| 2286 | + @Test |
| 2287 | + public void testDeleteNamespaceUsesRemoteClusterTlsConfig() throws Exception { |
| 2288 | + String remoteCluster = "remote-cluster-tls"; |
| 2289 | + // Test case 1: Remote cluster with TLS disabled - should use regular serviceUrl |
| 2290 | + ClusterData remoteClusterNoTls = ClusterDataImpl.builder() |
| 2291 | + .serviceUrl("http://remote:8080") |
| 2292 | + .serviceUrlTls("https://remote:8443") |
| 2293 | + .brokerClientTlsEnabled(false) // TLS disabled |
| 2294 | + .build(); |
| 2295 | + admin.clusters().createCluster(remoteCluster, remoteClusterNoTls); |
| 2296 | + |
| 2297 | + // Create tenant |
| 2298 | + String tenant = "test-tenant"; |
| 2299 | + Set<String> allowedClusters = Sets.newHashSet(conf.getClusterName(), remoteCluster); |
| 2300 | + TenantInfoImpl tenantInfo = TenantInfoImpl.builder() |
| 2301 | + .allowedClusters(allowedClusters) |
| 2302 | + .build(); |
| 2303 | + admin.tenants().createTenant(tenant, tenantInfo); |
| 2304 | + |
| 2305 | + // Create global namespace with replication only to remote cluster |
| 2306 | + String globalNamespace = tenant + "/test-ns-tls"; |
| 2307 | + admin.namespaces().createNamespace(globalNamespace); |
| 2308 | + |
| 2309 | + Set<String> replicationClusters = Sets.newHashSet(remoteCluster); |
| 2310 | + admin.namespaces().setNamespaceReplicationClusters(globalNamespace, replicationClusters); |
| 2311 | + |
| 2312 | + try { |
| 2313 | + // This should attempt to redirect to remote cluster using HTTP (not HTTPS) |
| 2314 | + // because remoteCluster has brokerClientTlsEnabled=false |
| 2315 | + admin.namespaces().deleteNamespace(globalNamespace); |
| 2316 | + fail("Expected redirection exception was not thrown"); |
| 2317 | + } catch (Exception e) { |
| 2318 | + // The exact error depends on whether the redirect URL is accessible |
| 2319 | + // but we can verify the request was attempted (connection refused to port 8080) |
| 2320 | + String message = e.getMessage(); |
| 2321 | + assertTrue(message.contains("8080") || message.contains("remote") |
| 2322 | + || message.contains("Connection") || message.contains("redirect"), |
| 2323 | + "Expected connection error to HTTP port, got: " + message); |
| 2324 | + } |
| 2325 | + |
| 2326 | + // Clean up namespace for next test |
| 2327 | + try { |
| 2328 | + admin.namespaces().deleteNamespace(globalNamespace, true); |
| 2329 | + } catch (Exception ignored) { |
| 2330 | + // Cleanup - ignore errors |
| 2331 | + } |
| 2332 | + |
| 2333 | + // Test case 2: Remote cluster with TLS enabled - should use TLS serviceUrl |
| 2334 | + String remoteClusterTls = "remote-cluster-tls-enabled"; |
| 2335 | + ClusterData remoteClusterWithTls = ClusterDataImpl.builder() |
| 2336 | + .serviceUrl("http://remote-tls:8080") |
| 2337 | + .serviceUrlTls("https://remote-tls:8443") |
| 2338 | + .brokerClientTlsEnabled(true) // TLS enabled |
| 2339 | + .build(); |
| 2340 | + admin.clusters().createCluster(remoteClusterTls, remoteClusterWithTls); |
| 2341 | + |
| 2342 | + // Update tenant to include new cluster |
| 2343 | + Set<String> allowedClustersWithTls = Sets.newHashSet(conf.getClusterName(), remoteCluster, remoteClusterTls); |
| 2344 | + TenantInfoImpl tenantInfoWithTls = TenantInfoImpl.builder() |
| 2345 | + .allowedClusters(allowedClustersWithTls) |
| 2346 | + .build(); |
| 2347 | + admin.tenants().updateTenant(tenant, tenantInfoWithTls); |
| 2348 | + |
| 2349 | + // Create another global namespace |
| 2350 | + String globalNamespaceTls = tenant + "/test-ns-tls-enabled"; |
| 2351 | + admin.namespaces().createNamespace(globalNamespaceTls); |
| 2352 | + Set<String> replicationClustersTls = Sets.newHashSet(remoteClusterTls); |
| 2353 | + admin.namespaces().setNamespaceReplicationClusters(globalNamespaceTls, replicationClustersTls); |
| 2354 | + |
| 2355 | + try { |
| 2356 | + // This should attempt to redirect to remote cluster using HTTPS (port 8443) |
| 2357 | + // because remoteClusterTls has brokerClientTlsEnabled=true |
| 2358 | + admin.namespaces().deleteNamespace(globalNamespaceTls); |
| 2359 | + fail("Expected redirection exception was not thrown"); |
| 2360 | + } catch (Exception e) { |
| 2361 | + // Verify the request was attempted to HTTPS port (8443) |
| 2362 | + String message = e.getMessage(); |
| 2363 | + assertTrue(message.contains("8443") || message.contains("remote-tls") |
| 2364 | + || message.contains("Connection") || message.contains("redirect"), |
| 2365 | + "Expected connection error to HTTPS port, got: " + message); |
| 2366 | + } |
| 2367 | + |
| 2368 | + // Test case 3: Remote cluster with TLS enabled but no TLS service URL |
| 2369 | + String remoteClusterNoTlsUrl = "remote-cluster-no-tls-url"; |
| 2370 | + ClusterData remoteClusterMissingTlsUrl = ClusterDataImpl.builder() |
| 2371 | + .serviceUrl("http://remote-no-tls:8080") |
| 2372 | + .serviceUrlTls(null) // No TLS URL provided |
| 2373 | + .brokerClientTlsEnabled(true) // TLS enabled but no URL |
| 2374 | + .build(); |
| 2375 | + admin.clusters().createCluster(remoteClusterNoTlsUrl, remoteClusterMissingTlsUrl); |
| 2376 | + |
| 2377 | + // Update tenant to include new cluster |
| 2378 | + Set<String> allowedClustersNoTlsUrl = Sets.newHashSet(conf.getClusterName(), remoteCluster, |
| 2379 | + remoteClusterTls, remoteClusterNoTlsUrl); |
| 2380 | + TenantInfoImpl tenantInfoNoTlsUrl = TenantInfoImpl.builder() |
| 2381 | + .allowedClusters(allowedClustersNoTlsUrl) |
| 2382 | + .build(); |
| 2383 | + admin.tenants().updateTenant(tenant, tenantInfoNoTlsUrl); |
| 2384 | + |
| 2385 | + // Create another global namespace |
| 2386 | + String globalNamespaceNoTlsUrl = tenant + "/test-ns-no-tls-url"; |
| 2387 | + admin.namespaces().createNamespace(globalNamespaceNoTlsUrl); |
| 2388 | + Set<String> replicationClustersNoTlsUrl = Sets.newHashSet(remoteClusterNoTlsUrl); |
| 2389 | + admin.namespaces().setNamespaceReplicationClusters(globalNamespaceNoTlsUrl, replicationClustersNoTlsUrl); |
| 2390 | + |
| 2391 | + try { |
| 2392 | + // This should throw a precondition failed error because TLS is enabled |
| 2393 | + // but no TLS service URL is provided |
| 2394 | + admin.namespaces().deleteNamespace(globalNamespaceNoTlsUrl); |
| 2395 | + fail("Expected precondition failed exception was not thrown"); |
| 2396 | + } catch (Exception e) { |
| 2397 | + String message = e.getMessage(); |
| 2398 | + assertTrue(message.contains("does not provide TLS encrypted service") |
| 2399 | + || message.contains("TLS") || message.contains("encrypted"), |
| 2400 | + "Expected TLS service error, got: " + message); |
| 2401 | + } |
| 2402 | + } |
2283 | 2403 | } |
0 commit comments