This is an automated email from the ASF dual-hosted git repository.
penghui pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar.git
The following commit(s) were added to refs/heads/master by this push:
new e246458 [Issue 9790] Support disabled the tenants/namespaces force
deletion in the broker.conf (#9819)
e246458 is described below
commit e24645852edeee6aa0850ce814384bedd6518e7a
Author: Fangbin Sun <[email protected]>
AuthorDate: Wed Mar 10 14:50:37 2021 +0800
[Issue 9790] Support disabled the tenants/namespaces force deletion in the
broker.conf (#9819)
### Motivation
Fixes #9790
### Modifications
- Add new configs below and keep the default value to `false`:
```
forceDeleteTenantAllowed=false
forceDeleteNamespaceAllowed=false
```
- Add unit tests for this change.
---
conf/broker.conf | 6 +++
.../apache/pulsar/broker/ServiceConfiguration.java | 12 +++++
.../pulsar/broker/admin/impl/NamespacesBase.java | 6 +++
.../pulsar/broker/admin/impl/TenantsBase.java | 7 +++
.../apache/pulsar/broker/admin/v1/Namespaces.java | 1 +
.../apache/pulsar/broker/admin/v2/Namespaces.java | 1 +
.../apache/pulsar/broker/admin/AdminApiTest.java | 52 ++++++++++++++++++++++
.../apache/pulsar/broker/admin/NamespacesTest.java | 40 +++++++++++++++++
site2/docs/reference-configuration.md | 2 +
9 files changed, 127 insertions(+)
diff --git a/conf/broker.conf b/conf/broker.conf
index 368a97a..c1d1f91 100644
--- a/conf/broker.conf
+++ b/conf/broker.conf
@@ -165,6 +165,12 @@ brokerDeleteInactivePartitionedTopicMetadataEnabled=false
# Topics that are inactive for longer than this value will be deleted
brokerDeleteInactiveTopicsMaxInactiveDurationSeconds=
+# Allow you to delete a tenant forcefully.
+forceDeleteTenantAllowed=false
+
+# Allow you to delete a namespace forcefully.
+forceDeleteNamespaceAllowed=false
+
# Max pending publish requests per connection to avoid keeping large number of
pending
# requests in memory. Default: 1000
maxPendingPublishdRequestsPerConnection=1000
diff --git
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
index 2087dc1..526c414 100644
---
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
+++
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
@@ -375,6 +375,18 @@ public class ServiceConfiguration implements
PulsarConfiguration {
private Integer brokerDeleteInactiveTopicsMaxInactiveDurationSeconds =
null;
@FieldContext(
+ category = CATEGORY_POLICIES,
+ doc = "Allow forced deletion of tenants. Default is false."
+ )
+ private boolean forceDeleteTenantAllowed = false;
+
+ @FieldContext(
+ category = CATEGORY_POLICIES,
+ doc = "Allow forced deletion of namespaces. Default is false."
+ )
+ private boolean forceDeleteNamespaceAllowed = false;
+
+ @FieldContext(
category = CATEGORY_POLICIES,
doc = "Max pending publish requests per connection to avoid keeping
large number of pending "
+ "requests in memory. Default: 1000"
diff --git
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java
index dfc265e..e20d2f8 100644
---
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java
+++
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java
@@ -325,6 +325,12 @@ public abstract class NamespacesBase extends AdminResource
{
validateTenantOperation(namespaceName.getTenant(),
TenantOperation.DELETE_NAMESPACE);
validatePoliciesReadOnlyAccess();
+ if (!pulsar().getConfiguration().isForceDeleteNamespaceAllowed()) {
+ asyncResponse.resume(
+ new RestException(Status.METHOD_NOT_ALLOWED, "Broker
doesn't allow forced deletion of namespaces"));
+ return;
+ }
+
// ensure that non-global namespace is directed to the correct cluster
if (!namespaceName.isGlobal()) {
validateClusterOwnership(namespaceName.getCluster());
diff --git
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java
index 11f8db6..390b1fb 100644
---
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java
+++
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java
@@ -227,6 +227,7 @@ public class TenantsBase extends PulsarWebResource {
@ApiOperation(value = "Delete a tenant and all namespaces and topics under
it.")
@ApiResponses(value = { @ApiResponse(code = 403, message = "The requester
doesn't have admin permissions"),
@ApiResponse(code = 404, message = "Tenant does not exist"),
+ @ApiResponse(code = 405, message = "Broker doesn't allow forced
deletion of tenants"),
@ApiResponse(code = 409, message = "The tenant still has active
namespaces") })
public void deleteTenant(@Suspended final AsyncResponse asyncResponse,
@PathParam("tenant") @ApiParam(value = "The tenant name") String
tenant,
@@ -290,6 +291,12 @@ public class TenantsBase extends PulsarWebResource {
}
protected void internalDeleteTenantForcefully(AsyncResponse asyncResponse,
String tenant) {
+ if (!pulsar().getConfiguration().isForceDeleteTenantAllowed()) {
+ asyncResponse.resume(
+ new RestException(Status.METHOD_NOT_ALLOWED, "Broker
doesn't allow forced deletion of tenants"));
+ return;
+ }
+
List<String> namespaces;
try {
namespaces = getListOfNamespaces(tenant);
diff --git
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/Namespaces.java
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/Namespaces.java
index b2cadd7..783a37b 100644
---
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/Namespaces.java
+++
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v1/Namespaces.java
@@ -196,6 +196,7 @@ public class Namespaces extends NamespacesBase {
@ApiResponse(code = 307, message = "Current broker doesn't serve
the namespace"),
@ApiResponse(code = 403, message = "Don't have admin permission"),
@ApiResponse(code = 404, message = "Property or cluster or
namespace doesn't exist"),
+ @ApiResponse(code = 405, message = "Broker doesn't allow forced
deletion of namespaces"),
@ApiResponse(code = 409, message = "Namespace is not empty") })
public void deleteNamespace(@Suspended final AsyncResponse asyncResponse,
@PathParam("property") String property,
@PathParam("cluster") String cluster, @PathParam("namespace")
String namespace,
diff --git
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java
index 3195f6b..42a9728 100644
---
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java
+++
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java
@@ -144,6 +144,7 @@ public class Namespaces extends NamespacesBase {
@ApiResponse(code = 307, message = "Current broker doesn't serve
the namespace"),
@ApiResponse(code = 403, message = "Don't have admin permission"),
@ApiResponse(code = 404, message = "Tenant or cluster or namespace
doesn't exist"),
+ @ApiResponse(code = 405, message = "Broker doesn't allow forced
deletion of namespaces"),
@ApiResponse(code = 409, message = "Namespace is not empty") })
public void deleteNamespace(@Suspended final AsyncResponse asyncResponse,
@PathParam("tenant") String tenant,
@PathParam("namespace") String namespace,
diff --git
a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java
b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java
index 6b121d8..98e4aac 100644
---
a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java
+++
b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java
@@ -1106,6 +1106,9 @@ public class AdminApiTest extends
MockedPulsarServiceBaseTest {
@Test
public void testDeleteTenantForcefully() throws Exception {
+ // allow forced deletion of tenants
+ pulsar.getConfiguration().setForceDeleteTenantAllowed(true);
+
String tenant = "my-tenant";
assertFalse(admin.tenants().getTenants().contains(tenant));
@@ -1134,6 +1137,9 @@ public class AdminApiTest extends
MockedPulsarServiceBaseTest {
// Expected: cannot delete non-empty tenant
}
+ // allow forced deletion of namespaces
+ pulsar.getConfiguration().setForceDeleteNamespaceAllowed(true);
+
// delete tenant forcefully
admin.tenants().deleteTenant(tenant, true);
assertFalse(admin.tenants().getTenants().contains(tenant));
@@ -1142,6 +1148,52 @@ public class AdminApiTest extends
MockedPulsarServiceBaseTest {
new TenantInfo(Sets.newHashSet("role1", "role2"),
Sets.newHashSet("test")));
assertTrue(admin.tenants().getTenants().contains(tenant));
assertTrue(admin.namespaces().getNamespaces(tenant).isEmpty());
+
+ // reset back to false
+ pulsar.getConfiguration().setForceDeleteTenantAllowed(false);
+ pulsar.getConfiguration().setForceDeleteNamespaceAllowed(false);
+ }
+
+ @Test
+ public void testForceDeleteTenantNotAllowed() throws Exception {
+ assertFalse(pulsar.getConfiguration().isForceDeleteTenantAllowed());
+
+ String tenant = "my-tenant";
+ assertFalse(admin.tenants().getTenants().contains(tenant));
+
+ // create tenant
+ admin.tenants().createTenant(tenant,
+ new TenantInfo(Sets.newHashSet("role1", "role2"),
Sets.newHashSet("test")));
+
+ assertTrue(admin.tenants().getTenants().contains(tenant));
+
+ // create namespace
+ String namespace = tenant + "/my-ns";
+ admin.namespaces().createNamespace("my-tenant/my-ns",
Sets.newHashSet("test"));
+
+ assertEquals(admin.namespaces().getNamespaces(tenant),
Lists.newArrayList("my-tenant/my-ns"));
+
+ // create topic
+ String topic = namespace + "/my-topic";
+ admin.topics().createPartitionedTopic(topic, 10);
+
+ assertFalse(admin.topics().getList(namespace).isEmpty());
+
+ try {
+ admin.tenants().deleteTenant(tenant, false);
+ fail("should have failed");
+ } catch (PulsarAdminException e) {
+ // Expected: cannot delete non-empty tenant
+ }
+
+ try {
+ admin.tenants().deleteTenant(tenant, true);
+ fail("should have failed");
+ } catch (PulsarAdminException e) {
+ // Expected: cannot delete due to broker is not allowed
+ }
+
+ assertTrue(admin.tenants().getTenants().contains(tenant));
}
@Test
diff --git
a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java
b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java
index f4260d4..bc6d902 100644
---
a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java
+++
b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java
@@ -1139,6 +1139,9 @@ public class NamespacesTest extends
MockedPulsarServiceBaseTest {
*/
@Test
public void testForceDeleteNamespace() throws Exception {
+ // allow forced deletion of namespaces
+ pulsar.getConfiguration().setForceDeleteNamespaceAllowed(true);
+
String namespace = BrokerTestUtil.newUniqueName(this.testTenant +
"/namespace");
String topic = namespace + "/topic";
String non_persistent_topic = "non-persistent://" + topic;
@@ -1163,6 +1166,43 @@ public class NamespacesTest extends
MockedPulsarServiceBaseTest {
admin.namespaces().createNamespace(namespace, 100);
topicList = admin.topics().getList(namespace);
assertTrue(topicList.isEmpty());
+
+ // reset back to false
+ pulsar.getConfiguration().setForceDeleteNamespaceAllowed(false);
+ }
+
+ @Test
+ public void testForceDeleteNamespaceNotAllowed() throws Exception {
+ assertFalse(pulsar.getConfiguration().isForceDeleteNamespaceAllowed());
+
+ String namespace = BrokerTestUtil.newUniqueName(this.testTenant +
"/namespace");
+ String topic = namespace + "/topic";
+ String non_persistent_topic = "non-persistent://" + topic;
+
+ admin.namespaces().createNamespace(namespace, 100);
+
+ admin.topics().createPartitionedTopic(topic, 10);
+
+ admin.topics().createNonPartitionedTopic(non_persistent_topic);
+
+ List<String> topicList = admin.topics().getList(namespace);
+ assertFalse(topicList.isEmpty());
+
+ try {
+ admin.namespaces().deleteNamespace(namespace, false);
+ fail("should have failed");
+ } catch (PulsarAdminException e) {
+ // Expected: Cannot delete non empty namespace
+ }
+
+ try {
+ admin.namespaces().deleteNamespace(namespace, true);
+ fail("should have failed");
+ } catch (PulsarAdminException e) {
+ // Expected: Cannot delete due to broker is not allowed
+ }
+
+
assertTrue(admin.namespaces().getNamespaces(this.testTenant).contains(namespace));
}
@Test
diff --git a/site2/docs/reference-configuration.md
b/site2/docs/reference-configuration.md
index 95b786f..8308f62 100644
--- a/site2/docs/reference-configuration.md
+++ b/site2/docs/reference-configuration.md
@@ -185,6 +185,8 @@ internalListenerName|Specify the internal listener name for
the broker.<br><br>*
|brokerDeleteInactiveTopicsFrequencySeconds| How often to check for inactive
topics |60|
| brokerDeleteInactiveTopicsMode | Set the mode to delete inactive topics.
<li> `delete_when_no_subscriptions`: delete the topic which has no
subscriptions or active producers. <li> `delete_when_subscriptions_caught_up`:
delete the topic whose subscriptions have no backlogs and which has no active
producers or consumers. | `delete_when_no_subscriptions` |
| brokerDeleteInactiveTopicsMaxInactiveDurationSeconds | Set the maximum
duration for inactive topics. If it is not specified, the
`brokerDeleteInactiveTopicsFrequencySeconds` parameter is adopted. | N/A |
+|forceDeleteTenantAllowed| Allow you to delete a tenant forcefully. |false|
+|forceDeleteNamespaceAllowed| Allow you to delete a namespace forcefully.
|false|
|messageExpiryCheckIntervalInMinutes| How frequently to proactively check and
purge expired messages |5|
|brokerServiceCompactionMonitorIntervalInSeconds| Interval between checks to
see if topics with compaction policies need to be compacted |60|
|delayedDeliveryEnabled|Whether to enable the delayed delivery for messages.
If disabled, messages will be immediately delivered and there will be no
tracking overhead.|true|