You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by mm...@apache.org on 2019/05/19 00:49:15 UTC

[pulsar] branch branch-2.3 updated (1f4a836 -> ea70a2c)

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

mmerli pushed a change to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git.


    from 1f4a836   fix cannot use size (type _Ctype_int) as type _Ctype_ulong (#4212)
     new 6a8d838  [pulsar-broker] add producer/consumer id in error-logging (#3961)
     new 5031142  [issue #3975] Bugfix NPE on non durable consumer (#3988)
     new dfd4cc2  Improve error handling for triggering function when input data does not conform with input topic schema (#3995)
     new c0f7f1c  Add bookkeeper client version constraint (#4013)
     new d22c993  [Issue 3987][pulsar-broker]Handle config is null when create tenant (#4019)
     new ab7887a  Handle subrecords in JsonSchema encoding (#4023)
     new d632e50  Fix the swagger files generated by removing troublesome class (#4024)
     new 08a25ba  Fix Python functions state which is completely broken (#4027)
     new a9e757c  For functions metrics, avoid having HELP (#4029)
     new b53b180  fix errors in sql doc (#4030)
     new a0976d6  ack records in datagenerator print sink (#4052)
     new 553d568  Upgrade athenz libraries (#4056)
     new ad1071a  improve data-generator source performance (#4058)
     new b4aff17  Fix update cli source sink (#4061)
     new 487eaff  [client] Set actual topic name to partitioned consumer (#4064)
     new f497feb  For functions metrics in prometheus also remove TYPE (#4081)
     new e4c62f5  Optimizing performance for Pulsar function archive download (#4082)
     new 4c2bb0c  [pulsar-function] support bookie authentication from function-worker (#4088)
     new 164d237  Revert dup consumer and related code (#4142)
     new cc4a0bf  Avoid potentially blocking method during topic ownership check (#4190)
     new cfaa1fd  Fix segfault in c++ producer (#4219)
     new 20695e9  [pulsar-function] fix broken backward compatibility with v1-namespace while registering function (#4224)
     new 389bd1f  Validate admin operation on topic with authoritative parameter (#4270)
     new ed19ef5  Upgrade to BookKeeper 4.9.2 (#4288)
     new cb3cd78  Add double quotation marks for metrics with remote_cluster (#4295)
     new ea70a2c  By default, auto configure the size of Bookie read/write cache (#4297)

The 26 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 conf/bookkeeper.conf                               |   13 +-
 conf/functions_worker.yml                          |   10 +
 conf/standalone.conf                               |   13 +-
 .../templates/functions_worker.yml                 |    9 +
 distribution/server/src/assemble/LICENSE.bin.txt   |   56 +-
 .../apache/bookkeeper/mledger/ManagedLedger.java   |    1 +
 .../bookkeeper/mledger/impl/ManagedLedgerImpl.java |   10 +
 pom.xml                                            |    4 +-
 .../pulsar/broker/admin/impl/FunctionsBase.java    |    3 +-
 .../broker/admin/impl/PersistentTopicsBase.java    |    2 +-
 .../apache/pulsar/broker/admin/impl/SinkBase.java  |    3 +-
 .../pulsar/broker/admin/impl/SourceBase.java       |    3 +-
 .../pulsar/broker/admin/impl/TenantsBase.java      |    3 +
 .../pulsar/broker/namespace/NamespaceService.java  |   12 +-
 .../apache/pulsar/broker/service/ServerCnx.java    |   16 +-
 .../broker/service/persistent/PersistentTopic.java |    2 +-
 .../pulsar/broker/stats/prometheus/TopicStats.java |    2 +-
 .../common/naming/NamespaceBundleFactory.java      |    4 +
 .../org/apache/pulsar/broker/admin/AdminTest.java  |    7 +
 .../api/PartitionedProducerConsumerTest.java       |    1 +
 .../client/api/SimpleProducerConsumerTest.java     |  112 -
 .../apache/pulsar/client/api/TopicReaderTest.java  |    4 +-
 .../client/impl/PatternTopicsConsumerImplTest.java |    1 +
 .../pulsar/client/impl/TopicsConsumerImplTest.java |    1 +
 .../apache/pulsar/client/admin/PulsarAdmin.java    |   23 +-
 .../pulsar/client/admin/PulsarAdminException.java  |   20 +-
 .../pulsar/client/admin/internal/BaseResource.java |    4 +-
 .../{WebTargets.java => ComponentResource.java}    |   40 +-
 .../client/admin/internal/FunctionsImpl.java       |  126 +-
 .../pulsar/client/admin/internal/SinkImpl.java     |   44 +-
 .../pulsar/client/admin/internal/SourceImpl.java   |   44 +-
 .../admin/internal/http/AsyncHttpConnector.java    |   14 +-
 .../internal/http/AsyncHttpConnectorProvider.java  |    5 +
 .../client/impl/auth/AuthenticationAthenz.java     |   10 +
 .../client/impl/auth/AuthenticationAthenzTest.java |   24 +
 pulsar-client-cpp/lib/ClientImpl.cc                |   13 -
 pulsar-client-cpp/lib/ConsumerImpl.cc              |   12 -
 pulsar-client-cpp/lib/ConsumerImpl.h               |    3 -
 pulsar-client-cpp/lib/ConsumerImplBase.h           |    1 -
 pulsar-client-cpp/lib/ProducerImpl.cc              |    4 +-
 pulsar-client-cpp/python/pulsar/schema/schema.py   |    2 +-
 pulsar-client-cpp/python/setup.py                  |    2 +-
 pulsar-client-cpp/tests/BasicEndToEndTest.cc       |   82 -
 .../java/org/apache/pulsar/admin/cli/CmdSinks.java |    7 +-
 .../org/apache/pulsar/admin/cli/CmdSources.java    |    8 +-
 .../org/apache/pulsar/admin/cli/TestCmdSinks.java  |   39 +-
 .../apache/pulsar/admin/cli/TestCmdSources.java    |   36 +
 .../apache/pulsar/client/impl/ConsumerBase.java    |    9 -
 .../apache/pulsar/client/impl/ConsumerImpl.java    |    4 -
 .../client/impl/MultiTopicsConsumerImpl.java       |   21 +-
 .../pulsar/client/impl/PulsarClientImpl.java       |   19 -
 .../pulsar/common/functions/FunctionConfig.java    |    2 +-
 .../org/apache/pulsar/common/io/SinkConfig.java    |    2 +-
 .../instance/stats/ComponentStatsManager.java      |    2 +-
 .../instance/stats/PrometheusTextFormat.java       |   82 +
 .../instance/src/main/python/state_context.py      |    3 +-
 .../functions/utils/FunctionConfigUtils.java       |    9 +
 .../pulsar/functions/utils/SinkConfigUtils.java    |    9 +
 .../org/apache/pulsar/functions/worker/Utils.java  |    8 +
 .../pulsar/functions/worker/WorkerConfig.java      |   15 +
 .../functions/worker/rest/api/ComponentImpl.java   |   15 +-
 .../io/datagenerator/DataGeneratorPrintSink.java   |    1 +
 .../io/datagenerator/DataGeneratorSource.java      |    6 +-
 site/scripts/python-doc-gen.sh                     |    2 +
 site2/.gitignore                                   |    1 +
 site2/docs/reference-configuration.md              |    6 +-
 site2/docs/sql-getting-started.md                  |    2 +-
 site2/website/static/swagger/swagger.json          | 7841 --------------------
 .../version-2.2.0/sql-getting-started.md           |    2 +-
 .../org/apache/pulsar/storm/PulsarSpoutTest.java   |    7 +-
 70 files changed, 629 insertions(+), 8294 deletions(-)
 copy pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/{WebTargets.java => ComponentResource.java} (52%)
 create mode 100644 pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/PrometheusTextFormat.java
 delete mode 100644 site2/website/static/swagger/swagger.json


[pulsar] 24/26: Upgrade to BookKeeper 4.9.2 (#4288)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit ed19ef5fc0213fb7966a75c9159f6b84f4f15635
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Thu May 16 20:16:22 2019 -0700

    Upgrade to BookKeeper 4.9.2 (#4288)
---
 distribution/server/src/assemble/LICENSE.bin.txt | 56 ++++++++++++------------
 pom.xml                                          |  2 +-
 pulsar-client-cpp/python/setup.py                |  2 +-
 3 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/distribution/server/src/assemble/LICENSE.bin.txt b/distribution/server/src/assemble/LICENSE.bin.txt
index da2da01..af125e2 100644
--- a/distribution/server/src/assemble/LICENSE.bin.txt
+++ b/distribution/server/src/assemble/LICENSE.bin.txt
@@ -365,32 +365,32 @@ The Apache Software License, Version 2.0
     - org.apache.logging.log4j-log4j-web-2.10.0.jar
  * Java Native Access JNA -- net.java.dev.jna-jna-4.2.0.jar
  * BookKeeper
-    - org.apache.bookkeeper-bookkeeper-common-4.9.0.jar
-    - org.apache.bookkeeper-bookkeeper-common-allocator-4.9.0.jar
-    - org.apache.bookkeeper-bookkeeper-proto-4.9.0.jar
-    - org.apache.bookkeeper-bookkeeper-server-4.9.0.jar
-    - org.apache.bookkeeper-bookkeeper-tools-framework-4.9.0.jar
-    - org.apache.bookkeeper-circe-checksum-4.9.0.jar
-    - org.apache.bookkeeper-cpu-affinity-4.9.0.jar
-    - org.apache.bookkeeper-statelib-4.9.0.jar
-    - org.apache.bookkeeper-stream-storage-api-4.9.0.jar
-    - org.apache.bookkeeper-stream-storage-common-4.9.0.jar
-    - org.apache.bookkeeper-stream-storage-java-client-4.9.0.jar
-    - org.apache.bookkeeper-stream-storage-java-client-base-4.9.0.jar
-    - org.apache.bookkeeper-stream-storage-proto-4.9.0.jar
-    - org.apache.bookkeeper-stream-storage-server-4.9.0.jar
-    - org.apache.bookkeeper-stream-storage-service-api-4.9.0.jar
-    - org.apache.bookkeeper-stream-storage-service-impl-4.9.0.jar
-    - org.apache.bookkeeper.http-http-server-4.9.0.jar
-    - org.apache.bookkeeper.http-vertx-http-server-4.9.0.jar
-    - org.apache.bookkeeper.stats-bookkeeper-stats-api-4.9.0.jar
-    - org.apache.bookkeeper.stats-prometheus-metrics-provider-4.9.0.jar
-    - org.apache.bookkeeper.tests-stream-storage-tests-common-4.9.0.jar
-    - org.apache.distributedlog-distributedlog-common-4.9.0.jar
-    - org.apache.distributedlog-distributedlog-core-4.9.0-tests.jar
-    - org.apache.distributedlog-distributedlog-core-4.9.0.jar
-    - org.apache.distributedlog-distributedlog-protocol-4.9.0.jar
-    - org.apache.bookkeeper.stats-codahale-metrics-provider-4.9.0.jar
+    - org.apache.bookkeeper-bookkeeper-common-4.9.2.jar
+    - org.apache.bookkeeper-bookkeeper-common-allocator-4.9.2.jar
+    - org.apache.bookkeeper-bookkeeper-proto-4.9.2.jar
+    - org.apache.bookkeeper-bookkeeper-server-4.9.2.jar
+    - org.apache.bookkeeper-bookkeeper-tools-framework-4.9.2.jar
+    - org.apache.bookkeeper-circe-checksum-4.9.2.jar
+    - org.apache.bookkeeper-cpu-affinity-4.9.2.jar
+    - org.apache.bookkeeper-statelib-4.9.2.jar
+    - org.apache.bookkeeper-stream-storage-api-4.9.2.jar
+    - org.apache.bookkeeper-stream-storage-common-4.9.2.jar
+    - org.apache.bookkeeper-stream-storage-java-client-4.9.2.jar
+    - org.apache.bookkeeper-stream-storage-java-client-base-4.9.2.jar
+    - org.apache.bookkeeper-stream-storage-proto-4.9.2.jar
+    - org.apache.bookkeeper-stream-storage-server-4.9.2.jar
+    - org.apache.bookkeeper-stream-storage-service-api-4.9.2.jar
+    - org.apache.bookkeeper-stream-storage-service-impl-4.9.2.jar
+    - org.apache.bookkeeper.http-http-server-4.9.2.jar
+    - org.apache.bookkeeper.http-vertx-http-server-4.9.2.jar
+    - org.apache.bookkeeper.stats-bookkeeper-stats-api-4.9.2.jar
+    - org.apache.bookkeeper.stats-prometheus-metrics-provider-4.9.2.jar
+    - org.apache.bookkeeper.tests-stream-storage-tests-common-4.9.2.jar
+    - org.apache.distributedlog-distributedlog-common-4.9.2.jar
+    - org.apache.distributedlog-distributedlog-core-4.9.2-tests.jar
+    - org.apache.distributedlog-distributedlog-core-4.9.2.jar
+    - org.apache.distributedlog-distributedlog-protocol-4.9.2.jar
+    - org.apache.bookkeeper.stats-codahale-metrics-provider-4.9.2.jar
  * LZ4 -- org.lz4-lz4-java-1.5.0.jar
  * AsyncHttpClient
     - org.asynchttpclient-async-http-client-2.7.0.jar
@@ -480,7 +480,7 @@ The Apache Software License, Version 2.0
   * JCTools - Java Concurrency Tools for the JVM
     - org.jctools-jctools-core-2.1.2.jar
   * Vertx
-    - io.vertx-vertx-auth-common-3.4.1.jar 
+    - io.vertx-vertx-auth-common-3.4.1.jar
     - io.vertx-vertx-core-3.4.1.jar
     - io.vertx-vertx-web-3.4.1.jar
 
@@ -504,7 +504,7 @@ MIT License
  * Animal Sniffer Annotations
     - org.codehaus.mojo-animal-sniffer-annotations-1.17.jar
  * The Checker Framework
-    - org.checkerframework-checker-compat-qual-2.5.2.jar 
+    - org.checkerframework-checker-compat-qual-2.5.2.jar
 
 Protocol Buffers License
  * Protocol Buffers
diff --git a/pom.xml b/pom.xml
index 7c3ccee..d7419e2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -142,7 +142,7 @@ flexible messaging model and an intuitive client API.</description>
     <!-- apache commons -->
     <commons-compress.version>1.15</commons-compress.version>
 
-    <bookkeeper.version>4.9.0</bookkeeper.version>
+    <bookkeeper.version>4.9.2</bookkeeper.version>
     <zookeeper.version>3.4.13</zookeeper.version>
     <netty.version>4.1.32.Final</netty.version>
     <storm.version>1.0.5</storm.version>
diff --git a/pulsar-client-cpp/python/setup.py b/pulsar-client-cpp/python/setup.py
index 3abf1d0..cd2a066 100644
--- a/pulsar-client-cpp/python/setup.py
+++ b/pulsar-client-cpp/python/setup.py
@@ -68,7 +68,7 @@ dependencies = [
     'six',
 
     # functions dependencies
-    "apache-bookkeeper-client>=4.9.1",
+    "apache-bookkeeper-client>=4.9.2",
     "prometheus_client",
     "ratelimit"
 ]


[pulsar] 09/26: For functions metrics, avoid having HELP (#4029)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit a9e757cd5a285dbaf96cf81df7c2477ee580fa0b
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Mon Apr 15 11:07:46 2019 -0700

    For functions metrics, avoid having HELP (#4029)
---
 .../instance/stats/ComponentStatsManager.java      |   2 +-
 .../instance/stats/PrometheusTextFormat.java       | 103 +++++++++++++++++++++
 2 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/ComponentStatsManager.java b/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/ComponentStatsManager.java
index 38a5de6..6b8fd6c 100644
--- a/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/ComponentStatsManager.java
+++ b/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/ComponentStatsManager.java
@@ -144,7 +144,7 @@ public abstract class ComponentStatsManager implements AutoCloseable {
     public String getStatsAsString() throws IOException {
         StringWriter outputWriter = new StringWriter();
 
-        TextFormat.write004(outputWriter, collectorRegistry.metricFamilySamples());
+        PrometheusTextFormat.write004(outputWriter, collectorRegistry.metricFamilySamples());
 
         return outputWriter.toString();
     }
diff --git a/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/PrometheusTextFormat.java b/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/PrometheusTextFormat.java
new file mode 100644
index 0000000..52d756d
--- /dev/null
+++ b/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/PrometheusTextFormat.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.pulsar.functions.instance.stats;
+
+import io.prometheus.client.Collector;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Enumeration;
+
+/**
+ * Provide Prometheus text format for a collection of metrics, without the HELP string
+ */
+public class PrometheusTextFormat {
+    /**
+     * Write out the text version 0.0.4 of the given MetricFamilySamples.
+     */
+    public static void write004(Writer writer, Enumeration<Collector.MetricFamilySamples> mfs) throws IOException {
+        /*
+         * See http://prometheus.io/docs/instrumenting/exposition_formats/ for the output format specification.
+         */
+        while (mfs.hasMoreElements()) {
+            Collector.MetricFamilySamples metricFamilySamples = mfs.nextElement();
+            writer.write("# TYPE ");
+            writer.write(metricFamilySamples.name);
+            writer.write(' ');
+            writer.write(typeString(metricFamilySamples.type));
+            writer.write('\n');
+
+            for (Collector.MetricFamilySamples.Sample sample : metricFamilySamples.samples) {
+                writer.write(sample.name);
+                if (sample.labelNames.size() > 0) {
+                    writer.write('{');
+                    for (int i = 0; i < sample.labelNames.size(); ++i) {
+                        writer.write(sample.labelNames.get(i));
+                        writer.write("=\"");
+                        writeEscapedLabelValue(writer, sample.labelValues.get(i));
+                        writer.write("\",");
+                    }
+                    writer.write('}');
+                }
+                writer.write(' ');
+                writer.write(Collector.doubleToGoString(sample.value));
+                if (sample.timestampMs != null) {
+                    writer.write(' ');
+                    writer.write(sample.timestampMs.toString());
+                }
+                writer.write('\n');
+            }
+        }
+    }
+
+    private static String typeString(Collector.Type t) {
+        switch (t) {
+        case GAUGE:
+            return "gauge";
+        case COUNTER:
+            return "counter";
+        case SUMMARY:
+            return "summary";
+        case HISTOGRAM:
+            return "histogram";
+        default:
+            return "untyped";
+        }
+    }
+
+    private static void writeEscapedLabelValue(Writer writer, String s) throws IOException {
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            switch (c) {
+            case '\\':
+                writer.append("\\\\");
+                break;
+            case '\"':
+                writer.append("\\\"");
+                break;
+            case '\n':
+                writer.append("\\n");
+                break;
+            default:
+                writer.append(c);
+            }
+        }
+    }
+
+}


[pulsar] 21/26: Fix segfault in c++ producer (#4219)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit cfaa1fd5d557bfbd0855d3105a052c95cd9b6cc8
Author: Ivan Kelly <iv...@apache.org>
AuthorDate: Tue May 7 00:37:46 2019 +0200

    Fix segfault in c++ producer (#4219)
    
    The sendTimer_ may not be initialized if connection doesn't come up
    correctly.
---
 pulsar-client-cpp/lib/ProducerImpl.cc | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/pulsar-client-cpp/lib/ProducerImpl.cc b/pulsar-client-cpp/lib/ProducerImpl.cc
index d738a44..5cf799b 100644
--- a/pulsar-client-cpp/lib/ProducerImpl.cc
+++ b/pulsar-client-cpp/lib/ProducerImpl.cc
@@ -673,7 +673,9 @@ void ProducerImpl::start() { HandlerBase::start(); }
 void ProducerImpl::shutdown() {
     Lock lock(mutex_);
     state_ = Closed;
-    sendTimer_->cancel();
+    if (sendTimer_) {
+        sendTimer_->cancel();
+    }
     producerCreatedPromise_.setFailed(ResultAlreadyClosed);
 }
 


[pulsar] 26/26: By default, auto configure the size of Bookie read/write cache (#4297)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit ea70a2c8bdba3b5f1b046334f8394b7a06e7efdb
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Fri May 17 17:16:50 2019 -0700

    By default, auto configure the size of Bookie read/write cache (#4297)
    
    * By default, auto configure the size of Bookie read/write cache
    
    * Updated ref docs
---
 conf/bookkeeper.conf                  | 13 ++++++++-----
 conf/standalone.conf                  | 13 ++++++++-----
 site2/docs/reference-configuration.md |  6 +++---
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/conf/bookkeeper.conf b/conf/bookkeeper.conf
index 9df49d2..da68a3d 100644
--- a/conf/bookkeeper.conf
+++ b/conf/bookkeeper.conf
@@ -628,12 +628,15 @@ httpServerClass=org.apache.bookkeeper.http.vertx.VertxHttpServer
 
 # Size of Write Cache. Memory is allocated from JVM direct memory.
 # Write cache is used to buffer entries before flushing into the entry log
-# For good performance, it should be big enough to hold a sub
-dbStorage_writeCacheMaxSizeMb=512
+# For good performance, it should be big enough to hold a substantial amount
+# of entries in the flush interval
+#  By default it will be allocated to 1/4th of the available direct memory
+dbStorage_writeCacheMaxSizeMb=
 
 # Size of Read cache. Memory is allocated from JVM direct memory.
 # This read cache is pre-filled doing read-ahead whenever a cache miss happens
-dbStorage_readAheadCacheMaxSizeMb=256
+#  By default it will be allocated to 1/4th of the available direct memory
+dbStorage_readAheadCacheMaxSizeMb=
 
 # How many entries to pre-fill in cache after a read cache miss
 dbStorage_readAheadCacheBatchSize=1000
@@ -645,8 +648,8 @@ dbStorage_readAheadCacheBatchSize=1000
 # Size of RocksDB block-cache. For best performance, this cache
 # should be big enough to hold a significant portion of the index
 # database which can reach ~2GB in some cases
-# Default is 256 MBytes
-dbStorage_rocksDB_blockCacheSize=268435456
+# Default is to use 10% of the direct memory size
+dbStorage_rocksDB_blockCacheSize=
 
 # Other RocksDB specific tunables
 dbStorage_rocksDB_writeBufferSizeMB=64
diff --git a/conf/standalone.conf b/conf/standalone.conf
index 22bbc70..edadc2a 100644
--- a/conf/standalone.conf
+++ b/conf/standalone.conf
@@ -461,12 +461,15 @@ ledgerStorageClass=org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage
 
 # Size of Write Cache. Memory is allocated from JVM direct memory.
 # Write cache is used to buffer entries before flushing into the entry log
-# For good performance, it should be big enough to hold a sub
-dbStorage_writeCacheMaxSizeMb=256
+# For good performance, it should be big enough to hold a substantial amount
+# of entries in the flush interval
+# By default it will be allocated to 1/4th of the available direct memory
+dbStorage_writeCacheMaxSizeMb=
 
 # Size of Read cache. Memory is allocated from JVM direct memory.
 # This read cache is pre-filled doing read-ahead whenever a cache miss happens
-dbStorage_readAheadCacheMaxSizeMb=64
+# By default it will be allocated to 1/4th of the available direct memory
+dbStorage_readAheadCacheMaxSizeMb=
 
 # How many entries to pre-fill in cache after a read cache miss
 dbStorage_readAheadCacheBatchSize=1000
@@ -480,8 +483,8 @@ flushInterval=60000
 # Size of RocksDB block-cache. For best performance, this cache
 # should be big enough to hold a significant portion of the index
 # database which can reach ~2GB in some cases
-# Default is 16 MBytes
-dbStorage_rocksDB_blockCacheSize=16777216
+# Default is to use 10% of the direct memory size
+dbStorage_rocksDB_blockCacheSize=
 
 # Other RocksDB specific tunables
 dbStorage_rocksDB_writeBufferSizeMB=4
diff --git a/site2/docs/reference-configuration.md b/site2/docs/reference-configuration.md
index 2865da3..ee94920 100644
--- a/site2/docs/reference-configuration.md
+++ b/site2/docs/reference-configuration.md
@@ -84,10 +84,10 @@ BookKeeper is a replicated log storage system that Pulsar uses for durable stora
 |useHostNameAsBookieID|Whether the bookie should use its hostname to register with the coordination service (e.g.: zookeeper service). When false, bookie will use its ipaddress for the registration.|false|
 |statsProviderClass||org.apache.bookkeeper.stats.prometheus.PrometheusMetricsProvider|
 |prometheusStatsHttpPort||8000|
-|dbStorage_writeCacheMaxSizeMb|Size of Write Cache. Memory is allocated from JVM direct memory. Write cache is used to buffer entries before flushing into the entry log For good performance, it should be big enough to hold a sub|512|
-|dbStorage_readAheadCacheMaxSizeMb|Size of Read cache. Memory is allocated from JVM direct memory. This read cache is pre-filled doing read-ahead whenever a cache miss happens|256|
+|dbStorage_writeCacheMaxSizeMb|Size of Write Cache. Memory is allocated from JVM direct memory. Write cache is used to buffer entries before flushing into the entry log For good performance, it should be big enough to hold a sub|25% of direct memory|
+|dbStorage_readAheadCacheMaxSizeMb|Size of Read cache. Memory is allocated from JVM direct memory. This read cache is pre-filled doing read-ahead whenever a cache miss happens|25% of direct memory|
 |dbStorage_readAheadCacheBatchSize|How many entries to pre-fill in cache after a read cache miss|1000|
-|dbStorage_rocksDB_blockCacheSize|Size of RocksDB block-cache. For best performance, this cache should be big enough to hold a significant portion of the index database which can reach ~2GB in some cases|268435456|
+|dbStorage_rocksDB_blockCacheSize|Size of RocksDB block-cache. For best performance, this cache should be big enough to hold a significant portion of the index database which can reach ~2GB in some cases|10% of direct memory|
 |dbStorage_rocksDB_writeBufferSizeMB||64|
 |dbStorage_rocksDB_sstSizeInMB||64|
 |dbStorage_rocksDB_blockSize||65536|


[pulsar] 02/26: [issue #3975] Bugfix NPE on non durable consumer (#3988)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 503114219807d2a887d73114e2b76fa82fbdf2ee
Author: Ezequiel Lovelle <ez...@gmail.com>
AuthorDate: Mon Apr 8 23:01:19 2019 -0300

    [issue #3975] Bugfix NPE on non durable consumer (#3988)
    
    *Motivation*
    
    Trying to fix #3975
    
    When a reset of a cursor is performed with some timestamp on a non-durable
    consumer the message finder will fail with null pointer exception due to
    `cursor.getName()` being null.
    
    *Modifications*
    
      - Add method overloading for `newNonDurableCursor()` with subscription name.
      - Fix method getNonDurableSubscription to call `newNonDurableCursor()` with
        proper subscription name
      - Add test to assert issue.
---
 .../main/java/org/apache/bookkeeper/mledger/ManagedLedger.java |  1 +
 .../org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java  | 10 ++++++++++
 .../pulsar/broker/service/persistent/PersistentTopic.java      |  2 +-
 .../java/org/apache/pulsar/client/api/TopicReaderTest.java     |  4 +++-
 4 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/ManagedLedger.java b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/ManagedLedger.java
index d6813e4..fd2f4bb 100644
--- a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/ManagedLedger.java
+++ b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/ManagedLedger.java
@@ -172,6 +172,7 @@ public interface ManagedLedger {
      * @return the new NonDurableCursor
      */
     ManagedCursor newNonDurableCursor(Position startCursorPosition) throws ManagedLedgerException;
+    ManagedCursor newNonDurableCursor(Position startPosition, String subscriptionName) throws ManagedLedgerException;
 
     /**
      * Delete a ManagedCursor asynchronously.
diff --git a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java
index 7b20995..efa3e08 100644
--- a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java
+++ b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java
@@ -832,6 +832,16 @@ public class ManagedLedgerImpl implements ManagedLedger, CreateCallback {
     }
 
     @Override
+    public ManagedCursor newNonDurableCursor(Position startCursorPosition, String cursorName)
+            throws ManagedLedgerException {
+        checkManagedLedgerIsOpen();
+        checkFenced();
+
+        return new NonDurableCursorImpl(bookKeeper, config, this, cursorName,
+                (PositionImpl) startCursorPosition);
+    }
+
+    @Override
     public Iterable<ManagedCursor> getCursors() {
         return cursors;
     }
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java
index e818bf6..667bfc0 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java
@@ -641,7 +641,7 @@ public class PersistentTopic implements Topic, AddEntryCallback {
             Position startPosition = new PositionImpl(ledgerId, entryId);
             ManagedCursor cursor = null;
             try {
-                cursor = ledger.newNonDurableCursor(startPosition);
+                cursor = ledger.newNonDurableCursor(startPosition, subscriptionName);
             } catch (ManagedLedgerException e) {
                 subscriptionFuture.completeExceptionally(e);
             }
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TopicReaderTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TopicReaderTest.java
index 6318974..a4cdcd9 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TopicReaderTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TopicReaderTest.java
@@ -34,7 +34,9 @@ import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import org.apache.pulsar.client.impl.BatchMessageIdImpl;
 import org.apache.pulsar.client.impl.MessageImpl;
+import org.apache.pulsar.client.impl.ReaderImpl;
 import org.apache.pulsar.common.policies.data.TopicStats;
+import org.apache.pulsar.common.util.RelativeTimeUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -479,7 +481,7 @@ public class TopicReaderTest extends ProducerConsumerBase {
             assertTrue(reader.hasMessageAvailable());
 
             String readOut = new String(reader.readNext().getData());
-            assertTrue(readOut.equals(content));
+            assertEquals(content, readOut);
             assertFalse(reader.hasMessageAvailable());
         }
 


[pulsar] 17/26: Optimizing performance for Pulsar function archive download (#4082)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit e4c62f5999861190def5ce5e69d743169a2ae823
Author: Boyang Jerry Peng <je...@gmail.com>
AuthorDate: Sat Apr 20 10:14:24 2019 -0700

    Optimizing performance for Pulsar function archive download (#4082)
    
    * Optimizing performance for download
    
    * fixing update and create
    
    * fix upload
    
    * remove commented out code
    
    * remove blank lines
    
    * fix error messages
    
    * fix for sources and sinks
    
    * fix getting exception
    
    * fix auth headers
    
    * cleaning up
    
    * fix print messages
---
 .../apache/pulsar/client/admin/PulsarAdmin.java    |  23 +++-
 .../pulsar/client/admin/PulsarAdminException.java  |  20 +++-
 .../pulsar/client/admin/internal/BaseResource.java |   4 +-
 .../client/admin/internal/ComponentResource.java   |  47 ++++++++
 .../client/admin/internal/FunctionsImpl.java       | 126 +++++++++++++++------
 .../pulsar/client/admin/internal/SinkImpl.java     |  44 ++++---
 .../pulsar/client/admin/internal/SourceImpl.java   |  44 ++++---
 .../admin/internal/http/AsyncHttpConnector.java    |  14 ++-
 .../internal/http/AsyncHttpConnectorProvider.java  |   5 +
 9 files changed, 242 insertions(+), 85 deletions(-)

diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/PulsarAdmin.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/PulsarAdmin.java
index 4731879..cf4d4ce 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/PulsarAdmin.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/PulsarAdmin.java
@@ -51,6 +51,7 @@ import org.apache.pulsar.client.api.AuthenticationFactory;
 import org.apache.pulsar.client.api.PulsarClientException;
 import org.apache.pulsar.client.impl.auth.AuthenticationDisabled;
 import org.apache.pulsar.client.impl.conf.ClientConfigurationData;
+import org.asynchttpclient.AsyncHttpClient;
 import org.glassfish.jersey.client.ClientConfig;
 import org.glassfish.jersey.client.ClientProperties;
 import org.glassfish.jersey.jackson.JacksonFeature;
@@ -81,6 +82,7 @@ public class PulsarAdmin implements Closeable {
     private final ResourceQuotas resourceQuotas;
     private final ClientConfigurationData clientConfigData;
     private final Client client;
+    private final AsyncHttpClient httpAsyncClient;
     private final String serviceUrl;
     private final Lookup lookups;
     private final Functions functions;
@@ -146,11 +148,13 @@ public class PulsarAdmin implements Closeable {
             auth.start();
         }
 
+        AsyncHttpConnectorProvider asyncConnectorProvider = new AsyncHttpConnectorProvider(clientConfigData);
+
         ClientConfig httpConfig = new ClientConfig();
         httpConfig.property(ClientProperties.FOLLOW_REDIRECTS, true);
         httpConfig.property(ClientProperties.ASYNC_THREADPOOL_SIZE, 8);
         httpConfig.register(MultiPartFeature.class);
-        httpConfig.connectorProvider(new AsyncHttpConnectorProvider(clientConfigData));
+        httpConfig.connectorProvider(asyncConnectorProvider);
 
         ClientBuilder clientBuilder = ClientBuilder.newBuilder()
                 .withConfig(httpConfig)
@@ -165,6 +169,10 @@ public class PulsarAdmin implements Closeable {
         this.serviceUrl = serviceUrl;
         root = client.target(serviceUrl);
 
+        this.httpAsyncClient = asyncConnectorProvider.getConnector(
+                Math.toIntExact(TimeUnit.SECONDS.toMillis(this.connectTimeout)),
+                Math.toIntExact(TimeUnit.SECONDS.toMillis(this.readTimeout))).getHttpClient();
+
         this.clusters = new ClustersImpl(root, auth);
         this.brokers = new BrokersImpl(root, auth);
         this.brokerStats = new BrokerStatsImpl(root, auth);
@@ -175,9 +183,9 @@ public class PulsarAdmin implements Closeable {
         this.nonPersistentTopics = new NonPersistentTopicsImpl(root, auth);
         this.resourceQuotas = new ResourceQuotasImpl(root, auth);
         this.lookups = new LookupImpl(root, auth, useTls);
-        this.functions = new FunctionsImpl(root, auth);
-        this.source = new SourceImpl(root, auth);
-        this.sink = new SinkImpl(root, auth);
+        this.functions = new FunctionsImpl(root, auth, httpAsyncClient);
+        this.source = new SourceImpl(root, auth, httpAsyncClient);
+        this.sink = new SinkImpl(root, auth, httpAsyncClient);
         this.worker = new WorkerImpl(root, auth);
         this.schemas = new SchemasImpl(root, auth);
         this.bookies = new BookiesImpl(root, auth);
@@ -396,6 +404,11 @@ public class PulsarAdmin implements Closeable {
             LOG.error("Failed to close the authentication service", e);
         }
         client.close();
-    }
 
+        try {
+            httpAsyncClient.close();
+        } catch (IOException e) {
+           LOG.error("Failed to close http async client", e);
+        }
+    }
 }
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/PulsarAdminException.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/PulsarAdminException.java
index 9961454..68f7c8d 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/PulsarAdminException.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/PulsarAdminException.java
@@ -23,10 +23,13 @@ import javax.ws.rs.ServerErrorException;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.MediaType;
 
+import lombok.extern.slf4j.Slf4j;
 import org.apache.pulsar.common.policies.data.ErrorData;
+import org.apache.pulsar.common.util.ObjectMapperFactory;
 
 
 @SuppressWarnings("serial")
+@Slf4j
 public class PulsarAdminException extends Exception {
     private static final int DEFAULT_STATUS_CODE = 500;
 
@@ -34,15 +37,20 @@ public class PulsarAdminException extends Exception {
     private final int statusCode;
 
     private static String getReasonFromServer(WebApplicationException e) {
-        if (MediaType.APPLICATION_JSON.equals(e.getResponse().getHeaderString("Content-Type"))) {
+        try {
+            return e.getResponse().readEntity(ErrorData.class).reason;
+        } catch (Exception ex) {
             try {
-                return e.getResponse().readEntity(ErrorData.class).reason;
-            } catch (Exception ex) {
-                // could not parse output to ErrorData class
-                return e.getMessage();
+                return ObjectMapperFactory.getThreadLocal().readValue(e.getResponse().getEntity().toString(), ErrorData.class).reason;
+            } catch (Exception ex1) {
+                try {
+                    return ObjectMapperFactory.getThreadLocal().readValue(e.getMessage(), ErrorData.class).reason;
+                } catch (Exception ex2) {
+                    // could not parse output to ErrorData class
+                    return e.getMessage();
+                }
             }
         }
-        return e.getMessage();
     }
 
     public PulsarAdminException(ClientErrorException e) {
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/BaseResource.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/BaseResource.java
index 8753ee1..bde02d2 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/BaseResource.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/BaseResource.java
@@ -37,7 +37,6 @@ import org.apache.pulsar.client.admin.PulsarAdminException;
 import org.apache.pulsar.client.admin.PulsarAdminException.ConflictException;
 import org.apache.pulsar.client.admin.PulsarAdminException.ConnectException;
 import org.apache.pulsar.client.admin.PulsarAdminException.GettingAuthenticationDataException;
-import org.apache.pulsar.client.admin.PulsarAdminException.HttpErrorException;
 import org.apache.pulsar.client.admin.PulsarAdminException.NotAllowedException;
 import org.apache.pulsar.client.admin.PulsarAdminException.NotAuthorizedException;
 import org.apache.pulsar.client.admin.PulsarAdminException.NotFoundException;
@@ -52,7 +51,7 @@ import org.slf4j.LoggerFactory;
 public abstract class BaseResource {
     private static final Logger log = LoggerFactory.getLogger(BaseResource.class);
 
-    private final Authentication auth;
+    protected final Authentication auth;
 
     protected BaseResource(Authentication auth) {
         this.auth = auth;
@@ -200,5 +199,4 @@ public abstract class BaseResource {
             throw new WebApplicationException(response);
         }
     }
-
 }
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/ComponentResource.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/ComponentResource.java
new file mode 100644
index 0000000..36b0b2d
--- /dev/null
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/ComponentResource.java
@@ -0,0 +1,47 @@
+/**
+ * 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.pulsar.client.admin.internal;
+
+import org.apache.pulsar.client.admin.PulsarAdminException;
+import org.apache.pulsar.client.api.Authentication;
+import org.asynchttpclient.RequestBuilder;
+
+import java.util.Map;
+
+public class ComponentResource extends BaseResource {
+
+    protected ComponentResource(Authentication auth) {
+        super(auth);
+    }
+
+    public RequestBuilder addAuthHeaders(RequestBuilder requestBuilder) throws PulsarAdminException {
+
+        try {
+            if (auth != null && auth.getAuthData().hasDataForHttp()) {
+                for (Map.Entry<String, String> header : auth.getAuthData().getHttpHeaders()) {
+                    requestBuilder.addHeader(header.getKey(), header.getValue());
+                }
+            }
+
+            return requestBuilder;
+        } catch (Throwable t) {
+            throw new PulsarAdminException.GettingAuthenticationDataException(t);
+        }
+    }
+}
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/FunctionsImpl.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/FunctionsImpl.java
index ac8d60d..2d5d6e5 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/FunctionsImpl.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/FunctionsImpl.java
@@ -20,6 +20,7 @@ package org.apache.pulsar.client.admin.internal;
 
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
+import io.netty.handler.codec.http.HttpHeaders;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.pulsar.client.admin.Functions;
@@ -32,6 +33,14 @@ import org.apache.pulsar.common.io.ConnectorDefinition;
 import org.apache.pulsar.common.policies.data.ErrorData;
 import org.apache.pulsar.common.policies.data.FunctionStats;
 import org.apache.pulsar.common.policies.data.FunctionStatus;
+import org.apache.pulsar.common.util.ObjectMapperFactory;
+import org.asynchttpclient.AsyncHandler;
+import org.asynchttpclient.AsyncHttpClient;
+import org.asynchttpclient.HttpResponseBodyPart;
+import org.asynchttpclient.HttpResponseStatus;
+import org.asynchttpclient.RequestBuilder;
+import org.asynchttpclient.request.body.multipart.FilePart;
+import org.asynchttpclient.request.body.multipart.StringPart;
 import org.glassfish.jersey.media.multipart.FormDataBodyPart;
 import org.glassfish.jersey.media.multipart.FormDataMultiPart;
 import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
@@ -42,21 +51,27 @@ import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.StandardCopyOption;
+import java.io.FileOutputStream;
+import java.nio.channels.FileChannel;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Future;
 import java.util.stream.Collectors;
 
+import static org.asynchttpclient.Dsl.get;
+import static org.asynchttpclient.Dsl.post;
+import static org.asynchttpclient.Dsl.put;
+
 @Slf4j
-public class FunctionsImpl extends BaseResource implements Functions {
+public class FunctionsImpl extends ComponentResource implements Functions {
 
     private final WebTarget functions;
+    private final AsyncHttpClient asyncHttpClient;
 
-    public FunctionsImpl(WebTarget web, Authentication auth) {
+    public FunctionsImpl(WebTarget web, Authentication auth, AsyncHttpClient asyncHttpClient) {
         super(auth);
         this.functions = web.path("/admin/v3/functions");
+        this.asyncHttpClient = asyncHttpClient;
     }
 
     @Override
@@ -145,18 +160,19 @@ public class FunctionsImpl extends BaseResource implements Functions {
     @Override
     public void createFunction(FunctionConfig functionConfig, String fileName) throws PulsarAdminException {
         try {
-            final FormDataMultiPart mp = new FormDataMultiPart();
+            RequestBuilder builder = post(functions.path(functionConfig.getTenant()).path(functionConfig.getNamespace()).path(functionConfig.getName()).getUri().toASCIIString())
+                    .addBodyPart(new StringPart("functionConfig", ObjectMapperFactory.getThreadLocal().writeValueAsString(functionConfig), MediaType.APPLICATION_JSON));
 
             if (fileName != null && !fileName.startsWith("builtin://")) {
                 // If the function code is built in, we don't need to submit here
-                mp.bodyPart(new FileDataBodyPart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM_TYPE));
+               builder.addBodyPart(new FilePart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM));
+            }
+            org.asynchttpclient.Response response = asyncHttpClient.executeRequest(addAuthHeaders(builder).build()).get();
+
+            if (response.getStatusCode() < 200 || response.getStatusCode() >= 300) {
+                throw getApiException(Response.status(response.getStatusCode()).entity(response.getResponseBody()).build());
             }
 
-            mp.bodyPart(new FormDataBodyPart("functionConfig",
-                new Gson().toJson(functionConfig),
-                MediaType.APPLICATION_JSON_TYPE));
-            request(functions.path(functionConfig.getTenant()).path(functionConfig.getNamespace()).path(functionConfig.getName()))
-                    .post(Entity.entity(mp, MediaType.MULTIPART_FORM_DATA), ErrorData.class);
         } catch (Exception e) {
             throw getApiException(e);
         }
@@ -192,18 +208,18 @@ public class FunctionsImpl extends BaseResource implements Functions {
     @Override
     public void updateFunction(FunctionConfig functionConfig, String fileName) throws PulsarAdminException {
         try {
-            final FormDataMultiPart mp = new FormDataMultiPart();
+            RequestBuilder builder = put(functions.path(functionConfig.getTenant()).path(functionConfig.getNamespace()).path(functionConfig.getName()).getUri().toASCIIString())
+                    .addBodyPart(new StringPart("functionConfig", ObjectMapperFactory.getThreadLocal().writeValueAsString(functionConfig), MediaType.APPLICATION_JSON));
 
             if (fileName != null && !fileName.startsWith("builtin://")) {
                 // If the function code is built in, we don't need to submit here
-                mp.bodyPart(new FileDataBodyPart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM_TYPE));
+                builder.addBodyPart(new FilePart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM));
             }
+            org.asynchttpclient.Response response = asyncHttpClient.executeRequest(addAuthHeaders(builder).build()).get();
 
-            mp.bodyPart(new FormDataBodyPart("functionConfig",
-                new Gson().toJson(functionConfig),
-                MediaType.APPLICATION_JSON_TYPE));
-            request(functions.path(functionConfig.getTenant()).path(functionConfig.getNamespace()).path(functionConfig.getName()))
-                    .put(Entity.entity(mp, MediaType.MULTIPART_FORM_DATA), ErrorData.class);
+            if (response.getStatusCode() < 200 || response.getStatusCode() >= 300) {
+                throw getApiException(Response.status(response.getStatusCode()).entity(response.getResponseBody()).build());
+            }
         } catch (Exception e) {
             throw getApiException(e);
         }
@@ -314,13 +330,14 @@ public class FunctionsImpl extends BaseResource implements Functions {
     @Override
     public void uploadFunction(String sourceFile, String path) throws PulsarAdminException {
         try {
-            final FormDataMultiPart mp = new FormDataMultiPart();
-
-            mp.bodyPart(new FileDataBodyPart("data", new File(sourceFile), MediaType.APPLICATION_OCTET_STREAM_TYPE));
+            RequestBuilder builder = post(functions.path("upload").getUri().toASCIIString())
+                    .addBodyPart(new FilePart("data", new File(sourceFile), MediaType.APPLICATION_OCTET_STREAM))
+                    .addBodyPart(new StringPart("path", path, MediaType.TEXT_PLAIN));
 
-            mp.bodyPart(new FormDataBodyPart("path", path, MediaType.TEXT_PLAIN_TYPE));
-            request(functions.path("upload"))
-                    .post(Entity.entity(mp, MediaType.MULTIPART_FORM_DATA), ErrorData.class);
+            org.asynchttpclient.Response response = asyncHttpClient.executeRequest(addAuthHeaders(builder).build()).get();
+            if (response.getStatusCode() < 200 || response.getStatusCode() >= 300) {
+                throw getApiException(Response.status(response.getStatusCode()).entity(response.getResponseBody()).build());
+            }
         } catch (Exception e) {
             throw getApiException(e);
         }
@@ -328,15 +345,58 @@ public class FunctionsImpl extends BaseResource implements Functions {
 
     @Override
     public void downloadFunction(String destinationPath, String path) throws PulsarAdminException {
+
+        HttpResponseStatus status;
         try {
-            InputStream response = request(functions.path("download")
-                    .queryParam("path", path)).get(InputStream.class);
-            if (response != null) {
-                File targetFile = new File(destinationPath);
-                java.nio.file.Files.copy(
-                        response,
-                        targetFile.toPath(),
-                        StandardCopyOption.REPLACE_EXISTING);
+            File file = new File(destinationPath);
+            if (!file.exists()) {
+                file.createNewFile();
+            }
+            FileChannel os = new FileOutputStream(new File(destinationPath)).getChannel();
+            WebTarget target = functions.path("download").queryParam("path", path);
+
+            RequestBuilder builder = get(target.getUri().toASCIIString());
+
+            Future<HttpResponseStatus> whenStatusCode
+                    = asyncHttpClient.executeRequest(addAuthHeaders(builder).build(), new AsyncHandler<HttpResponseStatus>() {
+                private HttpResponseStatus status;
+
+                @Override
+                public State onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
+                    status = responseStatus;
+                    if (status.getStatusCode() != Response.Status.OK.getStatusCode()) {
+                        return State.ABORT;
+                    }
+                    return State.CONTINUE;
+                }
+
+                @Override
+                public State onHeadersReceived(HttpHeaders headers) throws Exception {
+                    return State.CONTINUE;
+                }
+
+                @Override
+                public State onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
+
+                    os.write(bodyPart.getBodyByteBuffer());
+                    return State.CONTINUE;
+                }
+
+                @Override
+                public HttpResponseStatus onCompleted() throws Exception {
+                    return status;
+                }
+
+                @Override
+                public void onThrowable(Throwable t) {
+                }
+            });
+
+            status = whenStatusCode.get();
+            os.close();
+
+            if (status.getStatusCode() < 200 || status.getStatusCode() >= 300) {
+                throw getApiException(Response.status(status.getStatusCode()).entity(status.getStatusText()).build());
             }
         } catch (Exception e) {
             throw getApiException(e);
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/SinkImpl.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/SinkImpl.java
index 48a75e4..592d879 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/SinkImpl.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/SinkImpl.java
@@ -27,9 +27,13 @@ import org.apache.pulsar.common.io.ConnectorDefinition;
 import org.apache.pulsar.common.policies.data.ErrorData;
 import org.apache.pulsar.common.policies.data.SinkStatus;
 import org.apache.pulsar.common.io.SinkConfig;
+import org.apache.pulsar.common.util.ObjectMapperFactory;
+import org.asynchttpclient.AsyncHttpClient;
+import org.asynchttpclient.RequestBuilder;
+import org.asynchttpclient.request.body.multipart.FilePart;
+import org.asynchttpclient.request.body.multipart.StringPart;
 import org.glassfish.jersey.media.multipart.FormDataBodyPart;
 import org.glassfish.jersey.media.multipart.FormDataMultiPart;
-import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
 
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
@@ -39,14 +43,19 @@ import javax.ws.rs.core.Response;
 import java.io.File;
 import java.util.List;
 
+import static org.asynchttpclient.Dsl.post;
+import static org.asynchttpclient.Dsl.put;
+
 @Slf4j
-public class SinkImpl extends BaseResource implements Sink {
+public class SinkImpl extends ComponentResource implements Sink {
 
     private final WebTarget sink;
+    private final AsyncHttpClient asyncHttpClient;
 
-    public SinkImpl(WebTarget web, Authentication auth) {
+    public SinkImpl(WebTarget web, Authentication auth, AsyncHttpClient asyncHttpClient) {
         super(auth);
         this.sink = web.path("/admin/v3/sink");
+        this.asyncHttpClient = asyncHttpClient;
     }
 
     @Override
@@ -109,18 +118,19 @@ public class SinkImpl extends BaseResource implements Sink {
     @Override
     public void createSink(SinkConfig sinkConfig, String fileName) throws PulsarAdminException {
         try {
-            final FormDataMultiPart mp = new FormDataMultiPart();
+            RequestBuilder builder = post(sink.path(sinkConfig.getTenant()).path(sinkConfig.getNamespace()).path(sinkConfig.getName()).getUri().toASCIIString())
+                    .addBodyPart(new StringPart("sinkConfig", ObjectMapperFactory.getThreadLocal().writeValueAsString(sinkConfig), MediaType.APPLICATION_JSON));
 
             if (fileName != null && !fileName.startsWith("builtin://")) {
                 // If the function code is built in, we don't need to submit here
-                mp.bodyPart(new FileDataBodyPart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM_TYPE));
+                builder.addBodyPart(new FilePart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM));
+            }
+            org.asynchttpclient.Response response = asyncHttpClient.executeRequest(addAuthHeaders(builder).build()).get();
+
+            if (response.getStatusCode() < 200 || response.getStatusCode() >= 300) {
+                throw getApiException(Response.status(response.getStatusCode()).entity(response.getResponseBody()).build());
             }
 
-            mp.bodyPart(new FormDataBodyPart("sinkConfig",
-                new Gson().toJson(sinkConfig),
-                MediaType.APPLICATION_JSON_TYPE));
-            request(sink.path(sinkConfig.getTenant()).path(sinkConfig.getNamespace()).path(sinkConfig.getName()))
-                    .post(Entity.entity(mp, MediaType.MULTIPART_FORM_DATA), ErrorData.class);
         } catch (Exception e) {
             throw getApiException(e);
         }
@@ -156,18 +166,18 @@ public class SinkImpl extends BaseResource implements Sink {
     @Override
     public void updateSink(SinkConfig sinkConfig, String fileName) throws PulsarAdminException {
         try {
-            final FormDataMultiPart mp = new FormDataMultiPart();
+            RequestBuilder builder = put(sink.path(sinkConfig.getTenant()).path(sinkConfig.getNamespace()).path(sinkConfig.getName()).getUri().toASCIIString())
+                    .addBodyPart(new StringPart("sinkConfig", ObjectMapperFactory.getThreadLocal().writeValueAsString(sinkConfig), MediaType.APPLICATION_JSON));
 
             if (fileName != null && !fileName.startsWith("builtin://")) {
                 // If the function code is built in, we don't need to submit here
-                mp.bodyPart(new FileDataBodyPart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM_TYPE));
+                builder.addBodyPart(new FilePart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM));
             }
+            org.asynchttpclient.Response response = asyncHttpClient.executeRequest(addAuthHeaders(builder).build()).get();
 
-            mp.bodyPart(new FormDataBodyPart("sinkConfig",
-                    new Gson().toJson(sinkConfig),
-                MediaType.APPLICATION_JSON_TYPE));
-            request(sink.path(sinkConfig.getTenant()).path(sinkConfig.getNamespace()).path(sinkConfig.getName()))
-                    .put(Entity.entity(mp, MediaType.MULTIPART_FORM_DATA), ErrorData.class);
+            if (response.getStatusCode() < 200 || response.getStatusCode() >= 300) {
+                throw getApiException(Response.status(response.getStatusCode()).entity(response.getResponseBody()).build());
+            }
         } catch (Exception e) {
             throw getApiException(e);
         }
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/SourceImpl.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/SourceImpl.java
index 1a56dc4..5103375 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/SourceImpl.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/SourceImpl.java
@@ -27,9 +27,13 @@ import org.apache.pulsar.common.io.ConnectorDefinition;
 import org.apache.pulsar.common.policies.data.ErrorData;
 import org.apache.pulsar.common.io.SourceConfig;
 import org.apache.pulsar.common.policies.data.SourceStatus;
+import org.apache.pulsar.common.util.ObjectMapperFactory;
+import org.asynchttpclient.AsyncHttpClient;
+import org.asynchttpclient.RequestBuilder;
+import org.asynchttpclient.request.body.multipart.FilePart;
+import org.asynchttpclient.request.body.multipart.StringPart;
 import org.glassfish.jersey.media.multipart.FormDataBodyPart;
 import org.glassfish.jersey.media.multipart.FormDataMultiPart;
-import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
 
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
@@ -39,14 +43,19 @@ import javax.ws.rs.core.Response;
 import java.io.File;
 import java.util.List;
 
+import static org.asynchttpclient.Dsl.post;
+import static org.asynchttpclient.Dsl.put;
+
 @Slf4j
-public class SourceImpl extends BaseResource implements Source {
+public class SourceImpl extends ComponentResource implements Source {
 
     private final WebTarget source;
+    private final AsyncHttpClient asyncHttpClient;
 
-    public SourceImpl(WebTarget web, Authentication auth) {
+    public SourceImpl(WebTarget web, Authentication auth, AsyncHttpClient asyncHttpClient) {
         super(auth);
         this.source = web.path("/admin/v3/source");
+        this.asyncHttpClient = asyncHttpClient;
     }
 
     @Override
@@ -109,18 +118,17 @@ public class SourceImpl extends BaseResource implements Source {
     @Override
     public void createSource(SourceConfig sourceConfig, String fileName) throws PulsarAdminException {
         try {
-            final FormDataMultiPart mp = new FormDataMultiPart();
+            RequestBuilder builder = post(source.path(sourceConfig.getTenant()).path(sourceConfig.getNamespace()).path(sourceConfig.getName()).getUri().toASCIIString())
+                    .addBodyPart(new StringPart("sourceConfig", ObjectMapperFactory.getThreadLocal().writeValueAsString(sourceConfig), MediaType.APPLICATION_JSON));
 
             if (fileName != null && !fileName.startsWith("builtin://")) {
                 // If the function code is built in, we don't need to submit here
-                mp.bodyPart(new FileDataBodyPart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM_TYPE));
+                builder.addBodyPart(new FilePart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM));
+            }
+            org.asynchttpclient.Response response = asyncHttpClient.executeRequest(addAuthHeaders(builder).build()).get();
+            if (response.getStatusCode() < 200 || response.getStatusCode() >= 300) {
+                throw getApiException(Response.status(response.getStatusCode()).entity(response.getResponseBody()).build());
             }
-
-            mp.bodyPart(new FormDataBodyPart("sourceConfig",
-                new Gson().toJson(sourceConfig),
-                MediaType.APPLICATION_JSON_TYPE));
-            request(source.path(sourceConfig.getTenant()).path(sourceConfig.getNamespace()).path(sourceConfig.getName()))
-                    .post(Entity.entity(mp, MediaType.MULTIPART_FORM_DATA), ErrorData.class);
         } catch (Exception e) {
             throw getApiException(e);
         }
@@ -156,18 +164,18 @@ public class SourceImpl extends BaseResource implements Source {
     @Override
     public void updateSource(SourceConfig sourceConfig, String fileName) throws PulsarAdminException {
         try {
-            final FormDataMultiPart mp = new FormDataMultiPart();
+            RequestBuilder builder = put(source.path(sourceConfig.getTenant()).path(sourceConfig.getNamespace()).path(sourceConfig.getName()).getUri().toASCIIString())
+                    .addBodyPart(new StringPart("sourceConfig", ObjectMapperFactory.getThreadLocal().writeValueAsString(sourceConfig), MediaType.APPLICATION_JSON));
 
             if (fileName != null && !fileName.startsWith("builtin://")) {
                 // If the function code is built in, we don't need to submit here
-                mp.bodyPart(new FileDataBodyPart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM_TYPE));
+                builder.addBodyPart(new FilePart("data", new File(fileName), MediaType.APPLICATION_OCTET_STREAM));
             }
+            org.asynchttpclient.Response response = asyncHttpClient.executeRequest(addAuthHeaders(builder).build()).get();
 
-            mp.bodyPart(new FormDataBodyPart("sourceConfig",
-                    new Gson().toJson(sourceConfig),
-                MediaType.APPLICATION_JSON_TYPE));
-            request(source.path(sourceConfig.getTenant()).path(sourceConfig.getNamespace()).path(sourceConfig.getName()))
-                    .put(Entity.entity(mp, MediaType.MULTIPART_FORM_DATA), ErrorData.class);
+            if (response.getStatusCode() < 200 || response.getStatusCode() >= 300) {
+                throw getApiException(Response.status(response.getStatusCode()).entity(response.getResponseBody()).build());
+            }
         } catch (Exception e) {
             throw getApiException(e);
         }
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnector.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnector.java
index fd89108..dfb2ecc 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnector.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnector.java
@@ -34,6 +34,7 @@ import javax.ws.rs.client.Client;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response.Status;
 
+import lombok.Getter;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 
@@ -59,14 +60,21 @@ import org.glassfish.jersey.client.spi.Connector;
 @Slf4j
 public class AsyncHttpConnector implements Connector {
 
+    @Getter
     private final AsyncHttpClient httpClient;
 
-    @SneakyThrows
     public AsyncHttpConnector(Client client, ClientConfigurationData conf) {
+        this((int) client.getConfiguration().getProperty(ClientProperties.CONNECT_TIMEOUT),
+                (int) client.getConfiguration().getProperty(ClientProperties.READ_TIMEOUT),
+                conf);
+    }
+
+    @SneakyThrows
+    public AsyncHttpConnector(int connectTimeoutMs, int readTimeoutMs, ClientConfigurationData conf) {
         DefaultAsyncHttpClientConfig.Builder confBuilder = new DefaultAsyncHttpClientConfig.Builder();
         confBuilder.setFollowRedirect(true);
-        confBuilder.setConnectTimeout((int) client.getConfiguration().getProperty(ClientProperties.CONNECT_TIMEOUT));
-        confBuilder.setReadTimeout((int) client.getConfiguration().getProperty(ClientProperties.READ_TIMEOUT));
+        confBuilder.setConnectTimeout(connectTimeoutMs);
+        confBuilder.setReadTimeout(readTimeoutMs);
         confBuilder.setUserAgent(String.format("Pulsar-Java-v%s", PulsarVersion.getVersion()));
         confBuilder.setKeepAliveStrategy(new DefaultKeepAliveStrategy() {
             @Override
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnectorProvider.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnectorProvider.java
index 2f24089..1bddfe1 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnectorProvider.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnectorProvider.java
@@ -37,4 +37,9 @@ public class AsyncHttpConnectorProvider implements ConnectorProvider {
     public Connector getConnector(Client client, Configuration runtimeConfig) {
         return new AsyncHttpConnector(client, conf);
     }
+
+
+    public AsyncHttpConnector getConnector(int connectTimeoutMs, int readTimeoutMs) {
+        return new AsyncHttpConnector(connectTimeoutMs, readTimeoutMs, conf);
+    }
 }


[pulsar] 11/26: ack records in datagenerator print sink (#4052)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit a0976d655a964c247dbeb2d4ed24e9a77c40bd3b
Author: Boyang Jerry Peng <je...@gmail.com>
AuthorDate: Tue Apr 16 17:32:56 2019 -0700

    ack records in datagenerator print sink (#4052)
---
 .../java/org/apache/pulsar/io/datagenerator/DataGeneratorPrintSink.java  | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pulsar-io/data-generator/src/main/java/org/apache/pulsar/io/datagenerator/DataGeneratorPrintSink.java b/pulsar-io/data-generator/src/main/java/org/apache/pulsar/io/datagenerator/DataGeneratorPrintSink.java
index 6944247..2573958 100644
--- a/pulsar-io/data-generator/src/main/java/org/apache/pulsar/io/datagenerator/DataGeneratorPrintSink.java
+++ b/pulsar-io/data-generator/src/main/java/org/apache/pulsar/io/datagenerator/DataGeneratorPrintSink.java
@@ -36,6 +36,7 @@ public class DataGeneratorPrintSink implements Sink<Person> {
     @Override
     public void write(Record<Person> record) throws Exception {
         log.info("RECV: {}", record.getValue());
+        record.ack();
     }
 
     @Override


[pulsar] 25/26: Add double quotation marks for metrics with remote_cluster (#4295)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit cb3cd78ee36713cddc1de822e36c48cf53a56b8a
Author: tuteng <eg...@gmail.com>
AuthorDate: Sat May 18 01:00:47 2019 +0800

    Add double quotation marks for metrics with remote_cluster (#4295)
---
 .../main/java/org/apache/pulsar/broker/stats/prometheus/TopicStats.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/stats/prometheus/TopicStats.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/stats/prometheus/TopicStats.java
index 3549820..c009602 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/stats/prometheus/TopicStats.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/stats/prometheus/TopicStats.java
@@ -195,7 +195,7 @@ class TopicStats {
             String name, String remoteCluster, double value) {
         metricType(stream, name);
         stream.write(name).write("{cluster=\"").write(cluster).write("\",namespace=\"").write(namespace);
-        stream.write("\",topic=\"").write(topic).write("remote_cluster=\"").write(remoteCluster).write("\"} ");
+        stream.write("\",topic=\"").write(topic).write("\",remote_cluster=\"").write(remoteCluster).write("\"} ");
         stream.write(value).write(' ').write(System.currentTimeMillis()).write('\n');
     }
 }


[pulsar] 03/26: Improve error handling for triggering function when input data does not conform with input topic schema (#3995)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit dfd4cc2a9087314798b3152c8681708c2426115c
Author: Boyang Jerry Peng <je...@gmail.com>
AuthorDate: Sun Apr 7 23:06:07 2019 -0700

    Improve error handling for triggering function when input data does not conform with input topic schema (#3995)
---
 .../org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java     | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java
index ecc5180..d844972 100644
--- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java
+++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java
@@ -84,6 +84,7 @@ import org.apache.pulsar.client.api.Producer;
 import org.apache.pulsar.client.api.PulsarClientException;
 import org.apache.pulsar.client.api.Reader;
 import org.apache.pulsar.client.api.Schema;
+import org.apache.pulsar.client.api.SchemaSerializationException;
 import org.apache.pulsar.common.functions.FunctionConfig;
 import org.apache.pulsar.common.functions.FunctionState;
 import org.apache.pulsar.common.functions.WorkerInfo;
@@ -1136,6 +1137,8 @@ public abstract class ComponentImpl {
                 curTime = System.currentTimeMillis();
             }
             throw new RestException(Status.REQUEST_TIMEOUT, "Request Timed Out");
+        } catch (SchemaSerializationException e) {
+            throw new RestException(Status.BAD_REQUEST, String.format("Failed to serialize input with error: %s. Please check if input data conforms with the schema of the input topic.", e.getMessage()));
         } catch (IOException e) {
             throw new RestException(Status.INTERNAL_SERVER_ERROR, e.getMessage());
         } finally {


[pulsar] 13/26: improve data-generator source performance (#4058)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit ad1071a81e3e8eada4152dd84b3baeb47b92ed02
Author: Boyang Jerry Peng <je...@gmail.com>
AuthorDate: Wed Apr 17 22:31:54 2019 -0700

    improve data-generator source performance (#4058)
    
    ### Motivation
    
    Only initialize factory once in the beginning
---
 .../org/apache/pulsar/io/datagenerator/DataGeneratorSource.java     | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/pulsar-io/data-generator/src/main/java/org/apache/pulsar/io/datagenerator/DataGeneratorSource.java b/pulsar-io/data-generator/src/main/java/org/apache/pulsar/io/datagenerator/DataGeneratorSource.java
index 1a9f63f..118025a 100644
--- a/pulsar-io/data-generator/src/main/java/org/apache/pulsar/io/datagenerator/DataGeneratorSource.java
+++ b/pulsar-io/data-generator/src/main/java/org/apache/pulsar/io/datagenerator/DataGeneratorSource.java
@@ -29,9 +29,11 @@ import java.util.Optional;
 
 public class DataGeneratorSource implements Source<Person> {
 
+    private Fairy fairy;
+
     @Override
     public void open(Map<String, Object> config, SourceContext sourceContext) throws Exception {
-
+       this.fairy = Fairy.create();
     }
 
     @Override
@@ -45,7 +47,7 @@ public class DataGeneratorSource implements Source<Person> {
 
             @Override
             public Person getValue() {
-                return new Person(Fairy.create().person());
+                return new Person(fairy.person());
             }
         };
     }


[pulsar] 14/26: Fix update cli source sink (#4061)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit b4aff17c4e036ff06895dc6b2855c2af0266cac5
Author: Boyang Jerry Peng <je...@gmail.com>
AuthorDate: Wed Apr 17 17:42:38 2019 -0700

    Fix update cli source sink (#4061)
    
    * fix bug in source and sink cli update
    
    * fix import
    
    * fix logic
    
    * fix tests
---
 .../java/org/apache/pulsar/admin/cli/CmdSinks.java |  7 +++-
 .../org/apache/pulsar/admin/cli/CmdSources.java    |  8 ++++-
 .../org/apache/pulsar/admin/cli/TestCmdSinks.java  | 39 ++++++++++++++++++++--
 .../apache/pulsar/admin/cli/TestCmdSources.java    | 36 ++++++++++++++++++++
 .../pulsar/common/functions/FunctionConfig.java    |  2 +-
 .../org/apache/pulsar/common/io/SinkConfig.java    |  2 +-
 .../functions/utils/FunctionConfigUtils.java       |  9 +++++
 .../pulsar/functions/utils/SinkConfigUtils.java    |  9 +++++
 8 files changed, 105 insertions(+), 7 deletions(-)

diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdSinks.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdSinks.java
index 52842c3..cf60e8a 100644
--- a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdSinks.java
+++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdSinks.java
@@ -214,7 +214,12 @@ public class CmdSinks extends CmdBase {
         }
 
         protected void validateSinkConfigs(SinkConfig sinkConfig) {
-            org.apache.pulsar.common.functions.Utils.inferMissingArguments(sinkConfig);
+            if (sinkConfig.getTenant() == null) {
+                sinkConfig.setTenant(PUBLIC_TENANT);
+            }
+            if (sinkConfig.getNamespace() == null) {
+                sinkConfig.setNamespace(DEFAULT_NAMESPACE);
+            }
         }
     }
 
diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdSources.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdSources.java
index 3b1927e..01a6b38 100644
--- a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdSources.java
+++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdSources.java
@@ -207,6 +207,7 @@ public class CmdSources extends CmdBase {
 
     @Parameters(commandDescription = "Update a Pulsar IO source connector")
     protected class UpdateSource extends SourceDetailsCommand {
+
         @Override
         void runCmd() throws Exception {
             if (Utils.isFunctionPackageUrlSupported(sourceConfig.getArchive())) {
@@ -218,7 +219,12 @@ public class CmdSources extends CmdBase {
         }
 
         protected void validateSourceConfigs(SourceConfig sourceConfig) {
-            org.apache.pulsar.common.functions.Utils.inferMissingArguments(sourceConfig);
+            if (sourceConfig.getTenant() == null) {
+                sourceConfig.setTenant(PUBLIC_TENANT);
+            }
+            if (sourceConfig.getNamespace() == null) {
+                sourceConfig.setNamespace(DEFAULT_NAMESPACE);
+            }
         }
     }
 
diff --git a/pulsar-client-tools/src/test/java/org/apache/pulsar/admin/cli/TestCmdSinks.java b/pulsar-client-tools/src/test/java/org/apache/pulsar/admin/cli/TestCmdSinks.java
index 2bb3877..8340795 100644
--- a/pulsar-client-tools/src/test/java/org/apache/pulsar/admin/cli/TestCmdSinks.java
+++ b/pulsar-client-tools/src/test/java/org/apache/pulsar/admin/cli/TestCmdSinks.java
@@ -165,7 +165,6 @@ public class TestCmdSinks {
     @Test
     public void testMissingInput() throws Exception {
         SinkConfig sinkConfig = getSinkConfig();
-        sinkConfig.setInputSpecs(new HashMap<>());
         sinkConfig.setInputs(null);
         testCmdSinkCliMissingArgs(
                 TENANT,
@@ -190,7 +189,6 @@ public class TestCmdSinks {
         SinkConfig sinkConfig = getSinkConfig();
         sinkConfig.setTopicToSerdeClassName(null);
         sinkConfig.setTopicToSchemaType(null);
-        sinkConfig.setInputSpecs(new HashMap<>());
         testCmdSinkCliMissingArgs(
                 TENANT,
                 NAMESPACE,
@@ -212,7 +210,6 @@ public class TestCmdSinks {
     @Test
     public void testMissingTopicPattern() throws Exception {
         SinkConfig sinkConfig = getSinkConfig();
-        sinkConfig.getInputSpecs().clear();
         sinkConfig.setTopicsPattern(null);
         testCmdSinkCliMissingArgs(
                 TENANT,
@@ -677,4 +674,40 @@ public class TestCmdSinks {
 
         verify(sink).deleteSink(eq(TENANT), eq(NAMESPACE), null);
     }
+
+    @Test
+    public void testUpdateSink() throws Exception {
+
+        updateSink.name = "my-sink";
+
+        updateSink.archive = "new-archive";
+
+        updateSink.processArguments();
+
+        updateSink.runCmd();
+
+        verify(sink).updateSink(eq(SinkConfig.builder()
+                .tenant(PUBLIC_TENANT)
+                .namespace(DEFAULT_NAMESPACE)
+                .name(updateSink.name)
+                .archive(updateSink.archive)
+                .build()), eq(updateSink.archive));
+
+
+        updateSink.archive = null;
+
+        updateSink.parallelism = 2;
+
+        updateSink.processArguments();
+
+        updateSink.runCmd();
+
+        verify(sink).updateSink(eq(SinkConfig.builder()
+                .tenant(PUBLIC_TENANT)
+                .namespace(DEFAULT_NAMESPACE)
+                .name(updateSink.name)
+                .parallelism(2)
+                .build()), eq(null));
+
+    }
 }
diff --git a/pulsar-client-tools/src/test/java/org/apache/pulsar/admin/cli/TestCmdSources.java b/pulsar-client-tools/src/test/java/org/apache/pulsar/admin/cli/TestCmdSources.java
index 77e26a5..57dc3ce 100644
--- a/pulsar-client-tools/src/test/java/org/apache/pulsar/admin/cli/TestCmdSources.java
+++ b/pulsar-client-tools/src/test/java/org/apache/pulsar/admin/cli/TestCmdSources.java
@@ -570,4 +570,40 @@ public class TestCmdSources {
 
         verify(source).deleteSource(eq(TENANT), eq(NAMESPACE), null);
     }
+
+    @Test
+    public void testUpdateSource() throws Exception {
+
+        updateSource.name = "my-source";
+
+        updateSource.archive = "new-archive";
+
+        updateSource.processArguments();
+
+        updateSource.runCmd();
+
+        verify(source).updateSource(eq(SourceConfig.builder()
+                .tenant(PUBLIC_TENANT)
+                .namespace(DEFAULT_NAMESPACE)
+                .name(updateSource.name)
+                .archive(updateSource.archive)
+                .build()), eq(updateSource.archive));
+
+
+        updateSource.archive = null;
+
+        updateSource.parallelism = 2;
+
+        updateSource.processArguments();
+
+        updateSource.runCmd();
+
+        verify(source).updateSource(eq(SourceConfig.builder()
+                .tenant(PUBLIC_TENANT)
+                .namespace(DEFAULT_NAMESPACE)
+                .name(updateSource.name)
+                .parallelism(2)
+                .build()), eq(null));
+
+    }
 }
\ No newline at end of file
diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/functions/FunctionConfig.java b/pulsar-common/src/main/java/org/apache/pulsar/common/functions/FunctionConfig.java
index dc9023a..2b8883d 100644
--- a/pulsar-common/src/main/java/org/apache/pulsar/common/functions/FunctionConfig.java
+++ b/pulsar-common/src/main/java/org/apache/pulsar/common/functions/FunctionConfig.java
@@ -64,7 +64,7 @@ public class FunctionConfig {
     /**
      * A generalized way of specifying inputs
      */
-    private Map<String, ConsumerConfig> inputSpecs = new TreeMap<>();
+    private Map<String, ConsumerConfig> inputSpecs;
 
     private String output;
 
diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/io/SinkConfig.java b/pulsar-common/src/main/java/org/apache/pulsar/common/io/SinkConfig.java
index d6dd92c..6e51cbb 100644
--- a/pulsar-common/src/main/java/org/apache/pulsar/common/io/SinkConfig.java
+++ b/pulsar-common/src/main/java/org/apache/pulsar/common/io/SinkConfig.java
@@ -51,7 +51,7 @@ public class SinkConfig {
 
     private Map<String, String> topicToSchemaType;
 
-    private Map<String, ConsumerConfig> inputSpecs = new TreeMap<>();
+    private Map<String, ConsumerConfig> inputSpecs;
 
     private Map<String, Object> configs;
     // This is a map of secretName(aka how the secret is going to be
diff --git a/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java b/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java
index 05d6c83..c67de53 100644
--- a/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java
+++ b/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java
@@ -611,6 +611,15 @@ public class FunctionConfigUtils {
         if (!StringUtils.isEmpty(newConfig.getClassName())) {
             mergedConfig.setClassName(newConfig.getClassName());
         }
+
+        if (newConfig.getInputSpecs() == null) {
+            newConfig.setInputSpecs(new HashMap<>());
+        }
+
+        if (mergedConfig.getInputSpecs() == null) {
+            mergedConfig.setInputSpecs(new HashMap<>());
+        }
+        
         if (newConfig.getInputs() != null) {
             newConfig.getInputs().forEach((topicName -> {
                 newConfig.getInputSpecs().put(topicName,
diff --git a/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java b/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java
index f05a5f9..f1d7815 100644
--- a/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java
+++ b/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java
@@ -413,6 +413,15 @@ public class SinkConfigUtils {
         if (!StringUtils.isEmpty(newConfig.getSourceSubscriptionName()) && !newConfig.getSourceSubscriptionName().equals(existingConfig.getSourceSubscriptionName())) {
             throw new IllegalArgumentException("Subscription Name cannot be altered");
         }
+
+        if (newConfig.getInputSpecs() == null) {
+            newConfig.setInputSpecs(new HashMap<>());
+        }
+
+        if (mergedConfig.getInputSpecs() == null) {
+            mergedConfig.setInputSpecs(new HashMap<>());
+        }
+
         if (newConfig.getInputs() != null) {
             newConfig.getInputs().forEach((topicName -> {
                 newConfig.getInputSpecs().put(topicName,


[pulsar] 04/26: Add bookkeeper client version constraint (#4013)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit c0f7f1c45ca20db1c28ee8c7b5239539ec424c85
Author: Ali Ahmed <al...@gmail.com>
AuthorDate: Tue Apr 9 16:18:56 2019 -0700

    Add bookkeeper client version constraint (#4013)
    
    We require a certain version of bookkeeper client to operate python function state correctly.
---
 pulsar-client-cpp/python/setup.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pulsar-client-cpp/python/setup.py b/pulsar-client-cpp/python/setup.py
index 465097a..3abf1d0 100644
--- a/pulsar-client-cpp/python/setup.py
+++ b/pulsar-client-cpp/python/setup.py
@@ -68,7 +68,7 @@ dependencies = [
     'six',
 
     # functions dependencies
-    "apache-bookkeeper-client",
+    "apache-bookkeeper-client>=4.9.1",
     "prometheus_client",
     "ratelimit"
 ]


[pulsar] 05/26: [Issue 3987][pulsar-broker]Handle config is null when create tenant (#4019)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit d22c993f301a50036f8a2f1b51d8d3ef43edf8e0
Author: tuteng <eg...@gmail.com>
AuthorDate: Thu Apr 11 14:08:23 2019 +0800

    [Issue 3987][pulsar-broker]Handle config is null when create tenant (#4019)
    
    Fixes #3987
    
    ### Motivation
    
    Config will not appear null when create tenant use pulsar-admin create foo3, but use the following command, config is null.
    ```
    curl -X PUT http://localhost:8080/admin/v2/tenants/foo3
    ```
    
    ### Modifications
    
    Handle config is null when create tenant use curl.
    
    ### Verifying this change
    Test pass
    ```
    curl -X PUT http://localhost:8080/admin/v2/tenants/foo3
    curl -X GET http://localhost:8080/admin/v2/tenants/foo3
    {"adminRoles":[],"allowedClusters":[]}
    ```
---
 .../main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java | 3 +++
 .../src/test/java/org/apache/pulsar/broker/admin/AdminTest.java    | 7 +++++++
 2 files changed, 10 insertions(+)

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 cb3cd53..ee137f6 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
@@ -91,6 +91,9 @@ public class TenantsBase extends AdminResource {
 
         try {
             NamedEntity.checkName(tenant);
+            if (config == null) {
+                config = new TenantInfo();
+            }
             zkCreate(path(POLICIES, tenant), jsonMapper().writeValueAsBytes(config));
             log.info("[{}] Created tenant {}", clientAppId(), tenant);
         } catch (KeeperException.NodeExistsException e) {
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminTest.java
index b4f46aa..1cdd954 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminTest.java
@@ -499,8 +499,15 @@ public class AdminTest extends MockedPulsarServiceBaseTest {
             assertEquals(e.getResponse().getStatus(), Status.PRECONDITION_FAILED.getStatusCode());
         }
 
+        // Check tenantInfo is null
+        TenantInfo nullTenantInfo = new TenantInfo();
+        properties.createTenant("tenant-config-is-null", null);
+        assertEquals(properties.getTenantAdmin("tenant-config-is-null"), nullTenantInfo);
+
+
         namespaces.deleteNamespace("my-tenant", "use", "my-namespace", false);
         properties.deleteTenant("my-tenant");
+        properties.deleteTenant("tenant-config-is-null");
     }
 
     @Test


[pulsar] 08/26: Fix Python functions state which is completely broken (#4027)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 08a25ba8c4f4141873f3671465d29bf9f743fed1
Author: Ivan Kelly <iv...@apache.org>
AuthorDate: Thu Apr 11 20:32:24 2019 +0200

    Fix Python functions state which is completely broken (#4027)
    
    When a python functions instance is started with state enabled, it
    crashes because the state client cannot connect to the state
    endpoints. This is because the state client is *never* given the state
    endpoints, so there's no way it ever could connect.
---
 pulsar-functions/instance/src/main/python/state_context.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/pulsar-functions/instance/src/main/python/state_context.py b/pulsar-functions/instance/src/main/python/state_context.py
index ef8bbf4..9019483 100644
--- a/pulsar-functions/instance/src/main/python/state_context.py
+++ b/pulsar-functions/instance/src/main/python/state_context.py
@@ -126,7 +126,8 @@ class BKManagedStateContext(StateContext):
             ns.create(
                 stream_name=table_name,
                 stream_config=table_conf)
-        self.__client__ = kv.Client(namespace=table_ns)
+        self.__client__ = kv.Client(storage_client_settings=client_settings,
+                                    namespace=table_ns)
         self.__table__ = self.__client__.table(table_name=table_name)
 
     def incr(self, key, amount):


[pulsar] 10/26: fix errors in sql doc (#4030)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit b53b180ff7f5edc2fc5a3dec7662789534624aca
Author: Boyang Jerry Peng <je...@gmail.com>
AuthorDate: Fri Apr 12 09:35:46 2019 -0700

    fix errors in sql doc (#4030)
---
 site2/docs/sql-getting-started.md                                 | 2 +-
 site2/website/versioned_docs/version-2.2.0/sql-getting-started.md | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/site2/docs/sql-getting-started.md b/site2/docs/sql-getting-started.md
index 8aa06cd..0e673ac 100644
--- a/site2/docs/sql-getting-started.md
+++ b/site2/docs/sql-getting-started.md
@@ -72,7 +72,7 @@ Splits: 19 total, 19 done (100.00%)
 Currently, there is no data in Pulsar that we can query.  Lets start the built-in connector _DataGeneratorSource_ to ingest some mock data for us to query:
 
 ```bash
-./bin/pulsar-admin source create --tenant test-tenant --namespace test-namespace --name generator --destinationTopicName generator_test --source-type data-generator
+./bin/pulsar-admin source create --name generator --destinationTopicName generator_test --source-type data-generator
 ```
 
 Afterwards, the will be a topic with can query in the namespace "public/default":
diff --git a/site2/website/versioned_docs/version-2.2.0/sql-getting-started.md b/site2/website/versioned_docs/version-2.2.0/sql-getting-started.md
index 135fd73..2814ab0 100644
--- a/site2/website/versioned_docs/version-2.2.0/sql-getting-started.md
+++ b/site2/website/versioned_docs/version-2.2.0/sql-getting-started.md
@@ -73,7 +73,7 @@ Splits: 19 total, 19 done (100.00%)
 Currently, there is no data in Pulsar that we can query.  Lets start the built-in connector _DataGeneratorSource_ to ingest some mock data for us to query:
 
 ```bash
-./bin/pulsar-admin source create --tenant test-tenant --namespace test-namespace --name generator --destinationTopicName generator_test --source-type data-generator
+./bin/pulsar-admin source create --tenant public --namespace default --name generator --destinationTopicName generator_test --source-type data-generator
 ```
 
 Afterwards, the will be a topic with can query in the namespace "public/default":


[pulsar] 20/26: Avoid potentially blocking method during topic ownership check (#4190)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit cc4a0bfbeea1537ac34c3899a72af7f0d24f6042
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Wed May 1 18:58:10 2019 -0700

    Avoid potentially blocking method during topic ownership check (#4190)
---
 .../org/apache/pulsar/broker/namespace/NamespaceService.java | 12 +++++++++++-
 .../apache/pulsar/common/naming/NamespaceBundleFactory.java  |  4 ++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java
index 15174e2..b0f3cdc 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java
@@ -163,6 +163,11 @@ public class NamespaceService {
                 .thenApply(bundles -> bundles.findBundle(topic));
     }
 
+    public Optional<NamespaceBundle> getBundleIfPresent(TopicName topicName) throws Exception {
+        Optional<NamespaceBundles> bundles = bundleFactory.getBundlesIfPresent(topicName.getNamespaceObject());
+        return bundles.map(b -> b.findBundle(topicName));
+    }
+
     public NamespaceBundle getBundle(TopicName topicName) throws Exception {
         return bundleFactory.getBundles(topicName.getNamespaceObject()).findBundle(topicName);
     }
@@ -802,7 +807,12 @@ public class NamespaceService {
     }
 
     private boolean isTopicOwned(TopicName topicName) throws Exception {
-        return ownershipCache.getOwnedBundle(getBundle(topicName)) != null;
+        Optional<NamespaceBundle> bundle = getBundleIfPresent(topicName);
+        if (!bundle.isPresent()) {
+            return false;
+        } else {
+            return ownershipCache.getOwnedBundle(bundle.get()) != null;
+        }
     }
 
     public void removeOwnedServiceUnit(NamespaceName nsName) throws Exception {
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/common/naming/NamespaceBundleFactory.java b/pulsar-broker/src/main/java/org/apache/pulsar/common/naming/NamespaceBundleFactory.java
index af6ed3a..bb6924c 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/common/naming/NamespaceBundleFactory.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/common/naming/NamespaceBundleFactory.java
@@ -155,6 +155,10 @@ public class NamespaceBundleFactory implements ZooKeeperCacheListener<LocalPolic
         return bundlesCache.synchronous().get(nsname);
     }
 
+    public Optional<NamespaceBundles> getBundlesIfPresent(NamespaceName nsname) throws Exception {
+        return Optional.ofNullable(bundlesCache.synchronous().getIfPresent(nsname));
+    }
+
     public NamespaceBundle getBundle(NamespaceName nsname, Range<Long> hashRange) {
         return new NamespaceBundle(nsname, hashRange, this);
     }


[pulsar] 07/26: Fix the swagger files generated by removing troublesome class (#4024)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit d632e5078a7b2236d443ace77f2f1872cf5aaefc
Author: Sanjeev Kulkarni <sa...@gmail.com>
AuthorDate: Thu Apr 11 11:42:16 2019 -0700

    Fix the swagger files generated by removing troublesome class (#4024)
---
 .../pulsar/broker/admin/impl/FunctionsBase.java    |    3 +-
 .../apache/pulsar/broker/admin/impl/SinkBase.java  |    3 +-
 .../pulsar/broker/admin/impl/SourceBase.java       |    3 +-
 site/scripts/python-doc-gen.sh                     |    2 +
 site2/.gitignore                                   |    1 +
 site2/website/static/swagger/swagger.json          | 7841 --------------------
 6 files changed, 6 insertions(+), 7847 deletions(-)

diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java
index 9b88f29..80e26cb 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java
@@ -28,7 +28,6 @@ import org.apache.pulsar.common.functions.FunctionState;
 import org.apache.pulsar.common.io.ConnectorDefinition;
 import org.apache.pulsar.common.policies.data.FunctionStats;
 import org.apache.pulsar.common.policies.data.FunctionStatus;
-import org.apache.pulsar.functions.proto.Function.FunctionMetaData;
 import org.apache.pulsar.functions.worker.WorkerService;
 import org.apache.pulsar.functions.worker.rest.api.FunctionsImpl;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
@@ -126,7 +125,7 @@ public class FunctionsBase extends AdminResource implements Supplier<WorkerServi
     @GET
     @ApiOperation(
             value = "Fetches information about a Pulsar Function currently running in cluster mode",
-            response = FunctionMetaData.class
+            response = FunctionConfig.class
     )
     @ApiResponses(value = {
             @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"),
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinkBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinkBase.java
index 2bd22a4..c878d67 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinkBase.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinkBase.java
@@ -26,7 +26,6 @@ import org.apache.pulsar.broker.admin.AdminResource;
 import org.apache.pulsar.common.io.ConnectorDefinition;
 import org.apache.pulsar.common.io.SinkConfig;
 import org.apache.pulsar.common.policies.data.SinkStatus;
-import org.apache.pulsar.functions.proto.Function.FunctionMetaData;
 import org.apache.pulsar.functions.worker.WorkerService;
 import org.apache.pulsar.functions.worker.rest.api.SinkImpl;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
@@ -124,7 +123,7 @@ public class SinkBase extends AdminResource implements Supplier<WorkerService> {
     @GET
     @ApiOperation(
             value = "Fetches information about a Pulsar Sink currently running in cluster mode",
-            response = FunctionMetaData.class
+            response = SinkConfig.class
     )
     @ApiResponses(value = {
             @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"),
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourceBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourceBase.java
index 0e8348f..9fecadd 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourceBase.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourceBase.java
@@ -26,7 +26,6 @@ import org.apache.pulsar.broker.admin.AdminResource;
 import org.apache.pulsar.common.io.ConnectorDefinition;
 import org.apache.pulsar.common.io.SourceConfig;
 import org.apache.pulsar.common.policies.data.SourceStatus;
-import org.apache.pulsar.functions.proto.Function.FunctionMetaData;
 import org.apache.pulsar.functions.worker.WorkerService;
 import org.apache.pulsar.functions.worker.rest.api.SourceImpl;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
@@ -123,7 +122,7 @@ public class SourceBase extends AdminResource implements Supplier<WorkerService>
     @GET
     @ApiOperation(
             value = "Fetches information about a Pulsar Source currently running in cluster mode",
-            response = FunctionMetaData.class
+            response = SourceConfig.class
     )
     @ApiResponses(value = {
             @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"),
diff --git a/site/scripts/python-doc-gen.sh b/site/scripts/python-doc-gen.sh
index a6d197a..dbd9978 100755
--- a/site/scripts/python-doc-gen.sh
+++ b/site/scripts/python-doc-gen.sh
@@ -26,6 +26,8 @@ ROOT_DIR=$(git rev-parse --show-toplevel)
 # so that Pdoc can import the module
 find $ROOT_DIR -name CMakeCache.txt | xargs rm -f
 find $ROOT_DIR -name CMakeFiles | xargs rm -rf
+find $ROOT_DIR -name PulsarApi.pb.h | xargs rm -rf
+find $ROOT_DIR -name PulsarApi.pb.cc | xargs rm -rf
 cd $ROOT_DIR/pulsar-client-cpp
 cmake . 
 make -j8 _pulsar
diff --git a/site2/.gitignore b/site2/.gitignore
index 5395ea7..1fe366b 100644
--- a/site2/.gitignore
+++ b/site2/.gitignore
@@ -10,3 +10,4 @@ website/build/
 website/yarn.lock
 website/node_modules
 website/i18n/*
+website/static/swagger/*
diff --git a/site2/website/static/swagger/swagger.json b/site2/website/static/swagger/swagger.json
deleted file mode 100644
index 19ac427..0000000
--- a/site2/website/static/swagger/swagger.json
+++ /dev/null
@@ -1,7841 +0,0 @@
-{
-  "swagger" : "2.0",
-  "info" : {
-    "description" : "This provides the REST API for admin operations",
-    "version" : "v2",
-    "title" : "Pulsar Admin REST API",
-    "license" : {
-      "name" : "Apache 2.0",
-      "url" : "http://www.apache.org/licenses/LICENSE-2.0.html"
-    }
-  },
-  "basePath" : "/admin/v2",
-  "tags" : [ {
-    "name" : "bookies"
-  }, {
-    "name" : "broker-stats"
-  }, {
-    "name" : "brokers"
-  }, {
-    "name" : "clusters"
-  }, {
-    "name" : "namespaces"
-  }, {
-    "name" : "non-persistent topic"
-  }, {
-    "name" : "persistent topic"
-  }, {
-    "name" : "resource-quotas"
-  }, {
-    "name" : "schemas"
-  }, {
-    "name" : "tenants"
-  } ],
-  "schemes" : [ "http", "https" ],
-  "paths" : {
-    "/bookies/racks-info" : {
-      "get" : {
-        "tags" : [ "bookies" ],
-        "summary" : "Gets the rack placement information for all the bookies in the cluster",
-        "description" : "",
-        "operationId" : "getBookiesRackInfo",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "type" : "object",
-                "additionalProperties" : {
-                  "$ref" : "#/definitions/BookieInfo"
-                }
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/bookies/racks-info/{bookie}" : {
-      "get" : {
-        "tags" : [ "bookies" ],
-        "summary" : "Gets the rack placement information for a specific bookie in the cluster",
-        "description" : "",
-        "operationId" : "getBookieRackInfo",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "bookie",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/BookieInfo"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "bookies" ],
-        "summary" : "Updates the rack placement information for a specific bookie in the cluster",
-        "description" : "",
-        "operationId" : "updateBookieRackInfo",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "bookie",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "group",
-          "in" : "query",
-          "required" : false,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "bookies" ],
-        "summary" : "Removed the rack placement information for a specific bookie in the cluster",
-        "description" : "",
-        "operationId" : "deleteBookieRackInfo",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "bookie",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/broker-stats/allocator-stats/{allocator}" : {
-      "get" : {
-        "tags" : [ "broker-stats" ],
-        "summary" : "Get the stats for the Netty allocator. Available allocators are 'default' and 'ml-cache'",
-        "description" : "",
-        "operationId" : "getAllocatorStats",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "allocator",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/AllocatorStats"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/broker-stats/bookieops" : {
-      "get" : {
-        "tags" : [ "broker-stats" ],
-        "summary" : "Get pending bookie client op stats by namesapce",
-        "description" : "",
-        "operationId" : "getPendingBookieOpsStats",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "$ref" : "#/definitions/PendingBookieOpsStats"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/broker-stats/broker-resource-availability/{tenant}/{namespace}" : {
-      "get" : {
-        "tags" : [ "broker-stats" ],
-        "summary" : "Broker availability report",
-        "description" : "This API gives the current broker availability in percent, each resource percentage usage is calculated and thensum of all of the resource usage percent is called broker-resource-availability<br/><br/>THIS API IS ONLY FOR USE BY TESTING FOR CONFIRMING NAMESPACE ALLOCATION ALGORITHM",
-        "operationId" : "getBrokerResourceAvailability",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "$ref" : "#/definitions/ResourceUnit"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "409" : {
-            "description" : "Load-manager doesn't support operation"
-          }
-        }
-      }
-    },
-    "/broker-stats/load-report" : {
-      "get" : {
-        "tags" : [ "broker-stats" ],
-        "summary" : "Get Load for this broker",
-        "description" : "consists of topics stats & systemResourceUsage",
-        "operationId" : "getLoadReport",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/LoadReport"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/broker-stats/mbeans" : {
-      "get" : {
-        "tags" : [ "broker-stats" ],
-        "summary" : "Get all the mbean details of this broker JVM",
-        "description" : "",
-        "operationId" : "getMBeans",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "$ref" : "#/definitions/Metrics"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/broker-stats/metrics" : {
-      "get" : {
-        "tags" : [ "broker-stats" ],
-        "summary" : "Gets the metrics for Monitoring",
-        "description" : "Requested should be executed by Monitoring agent on each broker to fetch the metrics",
-        "operationId" : "getMetrics",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "$ref" : "#/definitions/Metrics"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/broker-stats/topics" : {
-      "get" : {
-        "tags" : [ "broker-stats" ],
-        "summary" : "Get all the topic stats by namesapce",
-        "description" : "",
-        "operationId" : "getTopics2",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/OutputStream"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/brokers/configuration" : {
-      "get" : {
-        "tags" : [ "brokers" ],
-        "summary" : "Get all updatable dynamic configurations's name",
-        "description" : "",
-        "operationId" : "getDynamicConfigurationName",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "object"
-              }
-            }
-          }
-        }
-      }
-    },
-    "/brokers/configuration/values" : {
-      "get" : {
-        "tags" : [ "brokers" ],
-        "summary" : "Get value of all dynamic configurations' value overridden on local config",
-        "description" : "",
-        "operationId" : "getAllDynamicConfigurations",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "type" : "object"
-              }
-            }
-          },
-          "404" : {
-            "description" : "Configuration not found"
-          }
-        }
-      }
-    },
-    "/brokers/configuration/{configName}/{configValue}" : {
-      "post" : {
-        "tags" : [ "brokers" ],
-        "summary" : "Update dynamic serviceconfiguration into zk only. This operation requires Pulsar super-user privileges.",
-        "description" : "",
-        "operationId" : "updateDynamicConfiguration",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "configName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "configValue",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "204" : {
-            "description" : "Service configuration updated successfully"
-          },
-          "403" : {
-            "description" : "You don't have admin permission to update service-configuration"
-          },
-          "404" : {
-            "description" : "Configuration not found"
-          },
-          "412" : {
-            "description" : "Configuration can't be updated dynamically"
-          }
-        }
-      }
-    },
-    "/brokers/internal-configuration" : {
-      "get" : {
-        "tags" : [ "brokers" ],
-        "summary" : "Get the internal configuration data",
-        "description" : "",
-        "operationId" : "getInternalConfigurationData",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/InternalConfigurationData"
-            }
-          }
-        }
-      }
-    },
-    "/brokers/{cluster}" : {
-      "get" : {
-        "tags" : [ "brokers" ],
-        "summary" : "Get the list of active brokers (web service addresses) in the cluster.",
-        "description" : "",
-        "operationId" : "getActiveBrokers",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "uniqueItems" : true,
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      }
-    },
-    "/brokers/{cluster}/{broker}/ownedNamespaces" : {
-      "get" : {
-        "tags" : [ "brokers" ],
-        "summary" : "Get the list of namespaces served by the specific broker",
-        "description" : "",
-        "operationId" : "getOwnedNamespaes",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "broker",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "$ref" : "#/definitions/NamespaceOwnershipStatus"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      }
-    },
-    "/clusters" : {
-      "get" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Get the list of all the Pulsar clusters.",
-        "description" : "",
-        "operationId" : "getClusters",
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "uniqueItems" : true,
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/clusters/{cluster}" : {
-      "get" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Get the configuration data for the specified cluster.",
-        "description" : "",
-        "operationId" : "getCluster",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/ClusterData"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Update the configuration for a cluster.",
-        "description" : "This operation requires Pulsar super-user privileges.",
-        "operationId" : "updateCluster",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "204" : {
-            "description" : "Cluster has been updated"
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Provisions a new cluster. This operation requires Pulsar super-user privileges.",
-        "description" : "The name cannot contain '/' characters.",
-        "operationId" : "createCluster",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "204" : {
-            "description" : "Cluster has been created"
-          },
-          "403" : {
-            "description" : "You don't have admin permission to create the cluster"
-          },
-          "409" : {
-            "description" : "Cluster already exists"
-          },
-          "412" : {
-            "description" : "Cluster name is not valid"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Delete an existing cluster",
-        "description" : "",
-        "operationId" : "deleteCluster",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "204" : {
-            "description" : "Cluster has been updated"
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Cluster doesn't exist"
-          },
-          "412" : {
-            "description" : "Cluster is not empty"
-          }
-        }
-      }
-    },
-    "/clusters/{cluster}/failureDomains" : {
-      "get" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Get the cluster failure domains",
-        "description" : "",
-        "operationId" : "getFailureDomains",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "$ref" : "#/definitions/FailureDomain"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/clusters/{cluster}/failureDomains/{domainName}" : {
-      "get" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Get a domain in a cluster",
-        "description" : "",
-        "operationId" : "getDomain",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "domainName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/FailureDomain"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Domain doesn't exist"
-          },
-          "412" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Set cluster's failure Domain",
-        "description" : "",
-        "operationId" : "setFailureDomain",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "domainName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Cluster doesn't exist"
-          },
-          "409" : {
-            "description" : "Broker already exists in another domain"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Delete cluster's failure omain",
-        "description" : "",
-        "operationId" : "deleteFailureDomain",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "domainName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission or plicy is read only"
-          },
-          "412" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      }
-    },
-    "/clusters/{cluster}/namespaceIsolationPolicies" : {
-      "get" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Get the namespace isolation policies assigned in the cluster",
-        "description" : "",
-        "operationId" : "getNamespaceIsolationPolicies",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "$ref" : "#/definitions/NamespaceIsolationData"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      }
-    },
-    "/clusters/{cluster}/namespaceIsolationPolicies/brokers" : {
-      "get" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Get list of brokers with namespace-isolation policies attached to them",
-        "description" : "",
-        "operationId" : "getBrokersWithNamespaceIsolationPolicy",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/BrokerNamespaceIsolationData"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace-isolation policies not found"
-          },
-          "412" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      }
-    },
-    "/clusters/{cluster}/namespaceIsolationPolicies/brokers/{broker}" : {
-      "get" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Get a broker with namespace-isolation policies attached to it",
-        "description" : "",
-        "operationId" : "getBrokerWithNamespaceIsolationPolicy",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "broker",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/BrokerNamespaceIsolationData"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace-isolation policies/ Broker not found"
-          },
-          "412" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      }
-    },
-    "/clusters/{cluster}/namespaceIsolationPolicies/{policyName}" : {
-      "get" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Get a single namespace isolation policy assigned in the cluster",
-        "description" : "",
-        "operationId" : "getNamespaceIsolationPolicy",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "policyName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/NamespaceIsolationData"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Policy doesn't exist"
-          },
-          "412" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Set namespace isolation policy",
-        "description" : "",
-        "operationId" : "setNamespaceIsolationPolicy",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "policyName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission or plicy is read only"
-          },
-          "412" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Delete namespace isolation policy",
-        "description" : "",
-        "operationId" : "deleteNamespaceIsolationPolicy",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "policyName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission or plicy is read only"
-          },
-          "412" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      }
-    },
-    "/clusters/{cluster}/peers" : {
-      "get" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Get the peer-cluster data for the specified cluster.",
-        "description" : "",
-        "operationId" : "getPeerCluster",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "uniqueItems" : true,
-              "items" : {
-                "type" : "object"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Cluster doesn't exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "clusters" ],
-        "summary" : "Update peer-cluster-list for a cluster.",
-        "description" : "This operation requires Pulsar super-user privileges.",
-        "operationId" : "setPeerClusterNames",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "204" : {
-            "description" : "Cluster has been updated"
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Cluster doesn't exist"
-          },
-          "412" : {
-            "description" : "Peer cluster doesn't exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{cluster}/antiAffinity/{group}" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get all namespaces that are grouped by given anti-affinity group in a given cluster. api can be only accessed by admin of any of the existing tenant",
-        "description" : "",
-        "operationId" : "getAntiAffinityNamespaces",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "group",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "tenant",
-          "in" : "query",
-          "required" : false,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "object"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "412" : {
-            "description" : "Cluster not exist/Anti-affinity group can't be empty."
-          }
-        }
-      }
-    },
-    "/namespaces/{property}/{namespace}/compactionThreshold" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Maximum number of uncompacted bytes in topics before compaction is triggered.",
-        "description" : "The backlog size is compared to the threshold periodically. A threshold of 0 disabled automatic compaction",
-        "operationId" : "getCompactionThreshold",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "property",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "integer",
-              "format" : "int64"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Set maximum number of uncompacted bytes in a topic before compaction is triggered.",
-        "description" : "The backlog size is compared to the threshold periodically. A threshold of 0 disabled automatic compaction",
-        "operationId" : "setCompactionThreshold",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "property",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          },
-          "412" : {
-            "description" : "compactionThreshold value is not valid"
-          }
-        }
-      }
-    },
-    "/namespaces/{property}/{namespace}/offloadDeletionLagMs" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Number of milliseconds to wait before deleting a ledger segment which has been offloaded from the Pulsar cluster's local storage (i.e. BookKeeper)",
-        "description" : "A negative value denotes that deletion has been completely disabled. 'null' denotes that the topics in the namespace will fall back to the broker default for deletion lag.",
-        "operationId" : "getOffloadDeletionLag",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "property",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "integer",
-              "format" : "int64"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Set number of milliseconds to wait before deleting a ledger segment which has been offloaded from the Pulsar cluster's local storage (i.e. BookKeeper)",
-        "description" : "A negative value disables the deletion completely.",
-        "operationId" : "setOffloadDeletionLag",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "property",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          },
-          "412" : {
-            "description" : "offloadDeletionLagMs value is not valid"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Clear the namespace configured offload deletion lag. The topics in the namespace will fallback to using the default configured deletion lag for the broker",
-        "description" : "",
-        "operationId" : "clearOffloadDeletionLag",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "property",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      }
-    },
-    "/namespaces/{property}/{namespace}/offloadThreshold" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Maximum number of bytes stored on the pulsar cluster for a topic, before the broker will start offloading to longterm storage",
-        "description" : "A negative value disables automatic offloading",
-        "operationId" : "getOffloadThreshold",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "property",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "integer",
-              "format" : "int64"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Set maximum number of bytes stored on the pulsar cluster for a topic, before the broker will start offloading to longterm storage",
-        "description" : "A negative value disables automatic offloading",
-        "operationId" : "setOffloadThreshold",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "property",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          },
-          "412" : {
-            "description" : "offloadThreshold value is not valid"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get the list of all the namespaces for a certain tenant.",
-        "description" : "",
-        "operationId" : "getTenantNamespaces",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "uniqueItems" : true,
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant doesn't exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get the dump all the policies specified for a namespace.",
-        "description" : "",
-        "operationId" : "getPolicies",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/Policies"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Creates a new namespace with the specified policies",
-        "description" : "",
-        "operationId" : "createNamespace",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster doesn't exist"
-          },
-          "409" : {
-            "description" : "Namespace already exists"
-          },
-          "412" : {
-            "description" : "Namespace name is not valid"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Delete a namespace and all the topics under it.",
-        "description" : "",
-        "operationId" : "deleteNamespace",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Namespace is not empty"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/antiAffinity" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get anti-affinity group of a namespace.",
-        "description" : "",
-        "operationId" : "getNamespaceAntiAffinityGroup",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "string"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Set anti-affinity group for a namespace",
-        "description" : "",
-        "operationId" : "setNamespaceAntiAffinityGroup",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "412" : {
-            "description" : "Invalid antiAffinityGroup"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Remove anti-affinity group of a namespace.",
-        "description" : "",
-        "operationId" : "removeNamespaceAntiAffinityGroup",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/backlogQuota" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : " Set a backlog quota for all the topics on a namespace.",
-        "description" : "",
-        "operationId" : "setBacklogQuota",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "backlogQuotaType",
-          "in" : "query",
-          "required" : false,
-          "type" : "string",
-          "enum" : [ "destination_storage" ]
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          },
-          "412" : {
-            "description" : "Specified backlog quota exceeds retention quota. Increase retention quota and retry request"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Remove a backlog quota policy from a namespace.",
-        "description" : "",
-        "operationId" : "removeBacklogQuota",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "backlogQuotaType",
-          "in" : "query",
-          "required" : false,
-          "type" : "string",
-          "enum" : [ "destination_storage" ]
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/backlogQuotaMap" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get backlog quota map on a namespace.",
-        "description" : "",
-        "operationId" : "getBacklogQuotaMap",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "type" : "object"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/bundles" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get the bundles split data.",
-        "description" : "",
-        "operationId" : "getBundlesData",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/BundlesData"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "412" : {
-            "description" : "Namespace is not setup to split in bundles"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/clearBacklog" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Clear backlog for all topics on a namespace.",
-        "description" : "",
-        "operationId" : "clearNamespaceBacklog",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/clearBacklog/{subscription}" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Clear backlog for a given subscription on all topics on a namespace.",
-        "description" : "",
-        "operationId" : "clearNamespaceBacklogForSubscription",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subscription",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/deduplication" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Enable or disable broker side deduplication for all topics in a namespace",
-        "description" : "",
-        "operationId" : "modifyDeduplication",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/dispatchRate" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get dispatch-rate configured for the namespace, -1 represents not configured yet",
-        "description" : "",
-        "operationId" : "getDispatchRate",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/DispatchRate"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Set dispatch-rate throttling for all topics of the namespace",
-        "description" : "",
-        "operationId" : "setDispatchRate",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/encryptionRequired" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Message encryption is required or not for all topics in a namespace",
-        "description" : "",
-        "operationId" : "modifyEncryptionRequired",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/maxConsumersPerSubscription" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get maxConsumersPerSubscription config on a namespace.",
-        "description" : "",
-        "operationId" : "getMaxConsumersPerSubscription",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "integer",
-              "format" : "int32"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : " Set maxConsumersPerSubscription configuration on a namespace.",
-        "description" : "",
-        "operationId" : "setMaxConsumersPerSubscription",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          },
-          "412" : {
-            "description" : "maxConsumersPerSubscription value is not valid"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/maxConsumersPerTopic" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get maxConsumersPerTopic config on a namespace.",
-        "description" : "",
-        "operationId" : "getMaxConsumersPerTopic",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "integer",
-              "format" : "int32"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : " Set maxConsumersPerTopic configuration on a namespace.",
-        "description" : "",
-        "operationId" : "setMaxConsumersPerTopic",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          },
-          "412" : {
-            "description" : "maxConsumersPerTopic value is not valid"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/maxProducersPerTopic" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get maxProducersPerTopic config on a namespace.",
-        "description" : "",
-        "operationId" : "getMaxProducersPerTopic",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "integer",
-              "format" : "int32"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : " Set maxProducersPerTopic configuration on a namespace.",
-        "description" : "",
-        "operationId" : "setMaxProducersPerTopic",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          },
-          "412" : {
-            "description" : "maxProducersPerTopic value is not valid"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/messageTTL" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get the message TTL for the namespace",
-        "description" : "",
-        "operationId" : "getNamespaceMessageTTL",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "integer",
-              "format" : "int32"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Set message TTL in seconds for namespace",
-        "description" : "",
-        "operationId" : "setNamespaceMessageTTL",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "412" : {
-            "description" : "Invalid TTL"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/permissions" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Retrieve the permissions for a namespace.",
-        "description" : "",
-        "operationId" : "getPermissions",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "type" : "object"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Namespace is not empty"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/permissions/{role}" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Grant a new permission to a role on a namespace.",
-        "description" : "",
-        "operationId" : "grantPermissionOnNamespace",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "role",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Revoke all permissions to a role on a namespace.",
-        "description" : "",
-        "operationId" : "revokePermissionsOnNamespace",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "role",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/persistence" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get the persistence configuration for a namespace.",
-        "description" : "",
-        "operationId" : "getPersistence",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PersistencePolicies"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Set the persistence configuration for all the topics on a namespace.",
-        "description" : "",
-        "operationId" : "setPersistence",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "400" : {
-            "description" : "Invalid persistence policies"
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/replication" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get the replication clusters for a namespace.",
-        "description" : "",
-        "operationId" : "getNamespaceReplicationClusters",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "412" : {
-            "description" : "Namespace is not global"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Set the replication clusters for a namespace.",
-        "description" : "",
-        "operationId" : "setNamespaceReplicationClusters",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Peer-cluster can't be part of replication-cluster"
-          },
-          "412" : {
-            "description" : "Namespace is not global or invalid cluster ids"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/retention" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get retention config on a namespace.",
-        "description" : "",
-        "operationId" : "getRetention",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/RetentionPolicies"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : " Set retention configuration on a namespace.",
-        "description" : "",
-        "operationId" : "setRetention",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          },
-          "412" : {
-            "description" : "Retention Quota must exceed backlog quota"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/subscriptionAuthMode" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : " Set a subscription auth mode for all the topics on a namespace.",
-        "description" : "",
-        "operationId" : "setSubscriptionAuthMode",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/subscriptionDispatchRate" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get Subscription dispatch-rate configured for the namespace, -1 represents not configured yet",
-        "description" : "",
-        "operationId" : "getSubscriptionDispatchRate",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/DispatchRate"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Set Subscription dispatch-rate throttling for all topics of the namespace",
-        "description" : "",
-        "operationId" : "setSubscriptionDispatchRate",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/topics" : {
-      "get" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Get the list of all the topics under a certain namespace.",
-        "description" : "",
-        "operationId" : "getTopics",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "uniqueItems" : true,
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/unload" : {
-      "put" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Unload namespace",
-        "description" : "Unload an active namespace from the current broker serving it. Performing this operation will let the brokerremoves all producers, consumers, and connections using this namespace, and close all topics (includingtheir persistent store). During that operation, the namespace is marked as tentatively unavailable until thebroker completes the unloading action. This operation requires strictly super user privileges, since it wouldresult in non-persistent message loss a [...]
-        "operationId" : "unloadNamespace",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or namespace doesn't exist"
-          },
-          "412" : {
-            "description" : "Namespace is already unloaded or Namespace has bundles activated"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/unsubscribe/{subscription}" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Unsubscribes the given subscription on all topics on a namespace.",
-        "description" : "",
-        "operationId" : "unsubscribeNamespace",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "cluster",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subscription",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/{bundle}" : {
-      "delete" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Delete a namespace bundle and all the topics under it.",
-        "description" : "",
-        "operationId" : "deleteNamespaceBundle",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Tenant or cluster or namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Namespace bundle is not empty"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/{bundle}/clearBacklog" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Clear backlog for all topics on a namespace bundle.",
-        "description" : "",
-        "operationId" : "clearNamespaceBundleBacklog",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/{bundle}/clearBacklog/{subscription}" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Clear backlog for a given subscription on all topics on a namespace bundle.",
-        "description" : "",
-        "operationId" : "clearNamespaceBundleBacklogForSubscription",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subscription",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/{bundle}/split" : {
-      "put" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Split a namespace bundle",
-        "description" : "",
-        "operationId" : "splitNamespaceBundle",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        }, {
-          "name" : "unload",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/{bundle}/unload" : {
-      "put" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Unload a namespace bundle",
-        "description" : "",
-        "operationId" : "unloadNamespaceBundle",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/namespaces/{tenant}/{namespace}/{bundle}/unsubscribe/{subscription}" : {
-      "post" : {
-        "tags" : [ "namespaces" ],
-        "summary" : "Unsubscribes the given subscription on all topics on a namespace bundle.",
-        "description" : "",
-        "operationId" : "unsubscribeNamespaceBundle",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subscription",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get the list of non-persistent topics under a namespace.",
-        "description" : "",
-        "operationId" : "getList",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/partitioned" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get the list of partitioned topics under a namespace.",
-        "description" : "",
-        "operationId" : "getPartitionedTopicList",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{bundle}" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get the list of non-persistent topics under a namespace bundle.",
-        "description" : "",
-        "operationId" : "getListFromBundle",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}" : {
-      "delete" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Delete a topic.",
-        "description" : "The topic cannot be deleted if delete is not forcefully and there's any active subscription or producer connected to the it. Force delete ignores connected clients and deletes topic by explicitly closing them.",
-        "operationId" : "deleteTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "force",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "412" : {
-            "description" : "Topic has active producers/subscriptions"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/all_subscription/expireMessages/{expireTimeInSeconds}" : {
-      "post" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Expire messages on all subscriptions of topic.",
-        "description" : "",
-        "operationId" : "expireMessagesForAllSubscriptions",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "expireTimeInSeconds",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int32"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic or subscription does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/backlog" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get estimated backlog for offline topic.",
-        "description" : "",
-        "operationId" : "getBacklog",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PersistentOfflineTopicStats"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/compaction" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get the status of a compaction operation for a topic.",
-        "description" : "",
-        "operationId" : "compactionStatus",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/LongRunningProcessStatus"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist, or compaction hasn't run"
-          },
-          "405" : {
-            "description" : "Operation not allowed on persistent topic"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Trigger a compaction operation on a topic.",
-        "description" : "",
-        "operationId" : "compact",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on persistent topic"
-          },
-          "409" : {
-            "description" : "Compaction already running"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/internal-info" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get the internal stats for the topic.",
-        "description" : "",
-        "operationId" : "getManagedLedgerInfo",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/internalStats" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get the internal stats for the topic.",
-        "description" : "",
-        "operationId" : "getInternalStats",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PersistentTopicInternalStats"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/offload" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Offload a prefix of a topic to long term storage",
-        "description" : "",
-        "operationId" : "offloadStatus",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/OffloadProcessStatus"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on persistent topic"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Offload a prefix of a topic to long term storage",
-        "description" : "",
-        "operationId" : "triggerOffload",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on persistent topic"
-          },
-          "409" : {
-            "description" : "Offload already running"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/partitioned-stats" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get the stats for the partitioned topic.",
-        "description" : "",
-        "operationId" : "getPartitionedStats",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PartitionedTopicStats"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/partitions" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get partitioned topic metadata.",
-        "description" : "",
-        "operationId" : "getPartitionedMetadata",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PartitionedTopicMetadata"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Increment partitons of an existing partitioned topic.",
-        "description" : "It only increments partitions of existing non-global partitioned-topic",
-        "operationId" : "updatePartitionedTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "409" : {
-            "description" : "Partitioned topic does not exist"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Create a partitioned topic.",
-        "description" : "It needs to be called before creating a producer on a partitioned topic.",
-        "operationId" : "createPartitionedTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "409" : {
-            "description" : "Partitioned topic already exists"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Delete a partitioned topic.",
-        "description" : "It will also delete all the partitions of the topic if it exists.",
-        "operationId" : "deletePartitionedTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "force",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Partitioned topic does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/permissions" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get permissions on a topic.",
-        "description" : "Retrieve the effective permissions for a topic. These permissions are defined by the permissions set at thenamespace level combined (union) with any eventual specific permission set on the topic.",
-        "operationId" : "getPermissionsOnTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "type" : "object"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/permissions/{role}" : {
-      "post" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Grant a new permission to a role on a single topic.",
-        "description" : "",
-        "operationId" : "grantPermissionsOnTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "role",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Revoke permissions on a topic.",
-        "description" : "Revoke permissions to a role on a single topic. If the permission was not set at the topiclevel, but rather at the namespace level, this operation will return an error (HTTP status code 412).",
-        "operationId" : "revokePermissionsOnTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "role",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          },
-          "412" : {
-            "description" : "Permissions are not set at the topic level"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/stats" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get the stats for the topic.",
-        "description" : "",
-        "operationId" : "getStats",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/TopicStats"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/subscription/{subName}" : {
-      "delete" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Delete a subscription.",
-        "description" : "There should not be any active consumers on the subscription.",
-        "operationId" : "deleteSubscription",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "412" : {
-            "description" : "Subscription has active consumers"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/expireMessages/{expireTimeInSeconds}" : {
-      "post" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Expire messages on a topic subscription.",
-        "description" : "",
-        "operationId" : "expireTopicMessages",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "expireTimeInSeconds",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int32"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic or subscription does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/position/{messagePosition}" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Peek nth message on a topic subscription.",
-        "description" : "",
-        "operationId" : "peekNthMessage",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "messagePosition",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int32"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic, subscription or the message position does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/resetcursor" : {
-      "post" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Reset subscription to message position closest to given position.",
-        "description" : "It fence cursor and disconnects all active consumers before reseting cursor.",
-        "operationId" : "resetCursorOnPosition",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic/Subscription does not exist"
-          },
-          "405" : {
-            "description" : "Not supported for partitioned topics"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/resetcursor/{timestamp}" : {
-      "post" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Reset subscription to message position closest to absolute timestamp (in ms).",
-        "description" : "It fence cursor and disconnects all active consumers before reseting cursor.",
-        "operationId" : "resetCursor",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "timestamp",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int64"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic/Subscription does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/skip/{numMessages}" : {
-      "post" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Skip messages on a topic subscription.",
-        "description" : "",
-        "operationId" : "skipMessages",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "numMessages",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int32"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic or subscription does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/skip_all" : {
-      "post" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Skip all messages on a topic subscription.",
-        "description" : "Completely clears the backlog on the subscription.",
-        "operationId" : "skipAllMessages",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic or subscription does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on non-persistent topic"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/subscription/{subscriptionName}" : {
-      "put" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Reset subscription to message position closest to given position.",
-        "description" : "Creates a subscription on the topic at the specified message id",
-        "operationId" : "createSubscription",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subscriptionName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic/Subscription does not exist"
-          },
-          "405" : {
-            "description" : "Not supported for partitioned topics"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/subscriptions" : {
-      "get" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Get the list of persistent subscriptions for a given topic.",
-        "description" : "",
-        "operationId" : "getSubscriptions",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "object"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/terminate" : {
-      "post" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Terminate a topic. A topic that is terminated will not accept any more messages to be published and will let consumer to drain existing messages in backlog",
-        "description" : "",
-        "operationId" : "terminate",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/MessageId"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on non-persistent topic"
-          }
-        }
-      }
-    },
-    "/non-persistent/{tenant}/{namespace}/{topic}/unload" : {
-      "put" : {
-        "tags" : [ "non-persistent topic" ],
-        "summary" : "Unload a topic",
-        "description" : "",
-        "operationId" : "unloadTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get the list of topics under a namespace.",
-        "description" : "",
-        "operationId" : "getList",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/partitioned" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get the list of partitioned topics under a namespace.",
-        "description" : "",
-        "operationId" : "getPartitionedTopicList",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}" : {
-      "delete" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Delete a topic.",
-        "description" : "The topic cannot be deleted if delete is not forcefully and there's any active subscription or producer connected to the it. Force delete ignores connected clients and deletes topic by explicitly closing them.",
-        "operationId" : "deleteTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "force",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "412" : {
-            "description" : "Topic has active producers/subscriptions"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/all_subscription/expireMessages/{expireTimeInSeconds}" : {
-      "post" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Expire messages on all subscriptions of topic.",
-        "description" : "",
-        "operationId" : "expireMessagesForAllSubscriptions",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "expireTimeInSeconds",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int32"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic or subscription does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/backlog" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get estimated backlog for offline topic.",
-        "description" : "",
-        "operationId" : "getBacklog",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PersistentOfflineTopicStats"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/compaction" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get the status of a compaction operation for a topic.",
-        "description" : "",
-        "operationId" : "compactionStatus",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/LongRunningProcessStatus"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist, or compaction hasn't run"
-          },
-          "405" : {
-            "description" : "Operation not allowed on persistent topic"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Trigger a compaction operation on a topic.",
-        "description" : "",
-        "operationId" : "compact",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on persistent topic"
-          },
-          "409" : {
-            "description" : "Compaction already running"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/internal-info" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get the internal stats for the topic.",
-        "description" : "",
-        "operationId" : "getManagedLedgerInfo",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/internalStats" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get the internal stats for the topic.",
-        "description" : "",
-        "operationId" : "getInternalStats",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PersistentTopicInternalStats"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/offload" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Offload a prefix of a topic to long term storage",
-        "description" : "",
-        "operationId" : "offloadStatus",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/OffloadProcessStatus"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on persistent topic"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Offload a prefix of a topic to long term storage",
-        "description" : "",
-        "operationId" : "triggerOffload",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on persistent topic"
-          },
-          "409" : {
-            "description" : "Offload already running"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/partitioned-stats" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get the stats for the partitioned topic.",
-        "description" : "",
-        "operationId" : "getPartitionedStats",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PartitionedTopicStats"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/partitions" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get partitioned topic metadata.",
-        "description" : "",
-        "operationId" : "getPartitionedMetadata",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PartitionedTopicMetadata"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Increment partitons of an existing partitioned topic.",
-        "description" : "It only increments partitions of existing non-global partitioned-topic",
-        "operationId" : "updatePartitionedTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "409" : {
-            "description" : "Partitioned topic does not exist"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Create a partitioned topic.",
-        "description" : "It needs to be called before creating a producer on a partitioned topic.",
-        "operationId" : "createPartitionedTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "409" : {
-            "description" : "Partitioned topic already exist"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Delete a partitioned topic.",
-        "description" : "It will also delete all the partitions of the topic if it exists.",
-        "operationId" : "deletePartitionedTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "force",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Partitioned topic does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/permissions" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get permissions on a topic.",
-        "description" : "Retrieve the effective permissions for a topic. These permissions are defined by the permissions set at thenamespace level combined (union) with any eventual specific permission set on the topic.",
-        "operationId" : "getPermissionsOnTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "object",
-              "additionalProperties" : {
-                "type" : "object"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/permissions/{role}" : {
-      "post" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Grant a new permission to a role on a single topic.",
-        "description" : "",
-        "operationId" : "grantPermissionsOnTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "role",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Revoke permissions on a topic.",
-        "description" : "Revoke permissions to a role on a single topic. If the permission was not set at the topiclevel, but rather at the namespace level, this operation will return an error (HTTP status code 412).",
-        "operationId" : "revokePermissionsOnTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "role",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace doesn't exist"
-          },
-          "412" : {
-            "description" : "Permissions are not set at the topic level"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/stats" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get the stats for the topic.",
-        "description" : "",
-        "operationId" : "getStats",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/TopicStats"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/subscription/{subName}" : {
-      "delete" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Delete a subscription.",
-        "description" : "There should not be any active consumers on the subscription.",
-        "operationId" : "deleteSubscription",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "412" : {
-            "description" : "Subscription has active consumers"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/expireMessages/{expireTimeInSeconds}" : {
-      "post" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Expire messages on a topic subscription.",
-        "description" : "",
-        "operationId" : "expireTopicMessages",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "expireTimeInSeconds",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int32"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic or subscription does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/position/{messagePosition}" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Peek nth message on a topic subscription.",
-        "description" : "",
-        "operationId" : "peekNthMessage",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "messagePosition",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int32"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic, subscription or the message position does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/resetcursor" : {
-      "post" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Reset subscription to message position closest to given position.",
-        "description" : "It fence cursor and disconnects all active consumers before reseting cursor.",
-        "operationId" : "resetCursorOnPosition",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic/Subscription does not exist"
-          },
-          "405" : {
-            "description" : "Not supported for partitioned topics"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/resetcursor/{timestamp}" : {
-      "post" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Reset subscription to message position closest to absolute timestamp (in ms).",
-        "description" : "It fence cursor and disconnects all active consumers before reseting cursor.",
-        "operationId" : "resetCursor",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "timestamp",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int64"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic/Subscription does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/skip/{numMessages}" : {
-      "post" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Skip messages on a topic subscription.",
-        "description" : "",
-        "operationId" : "skipMessages",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "numMessages",
-          "in" : "path",
-          "required" : true,
-          "type" : "integer",
-          "format" : "int32"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic or subscription does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/subscription/{subName}/skip_all" : {
-      "post" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Skip all messages on a topic subscription.",
-        "description" : "Completely clears the backlog on the subscription.",
-        "operationId" : "skipAllMessages",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic or subscription does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on non-persistent topic"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/subscription/{subscriptionName}" : {
-      "put" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Reset subscription to message position closest to given position.",
-        "description" : "Creates a subscription on the topic at the specified message id",
-        "operationId" : "createSubscription",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "subscriptionName",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic/Subscription does not exist"
-          },
-          "405" : {
-            "description" : "Not supported for partitioned topics"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/subscriptions" : {
-      "get" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Get the list of persistent subscriptions for a given topic.",
-        "description" : "",
-        "operationId" : "getSubscriptions",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "object"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/terminate" : {
-      "post" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Terminate a topic. A topic that is terminated will not accept any more messages to be published and will let consumer to drain existing messages in backlog",
-        "description" : "",
-        "operationId" : "terminate",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/MessageId"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          },
-          "405" : {
-            "description" : "Operation not allowed on non-persistent topic"
-          }
-        }
-      }
-    },
-    "/persistent/{tenant}/{namespace}/{topic}/unload" : {
-      "put" : {
-        "tags" : [ "persistent topic" ],
-        "summary" : "Unload a topic",
-        "description" : "",
-        "operationId" : "unloadTopic",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "authoritative",
-          "in" : "query",
-          "required" : false,
-          "type" : "boolean",
-          "default" : false
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Topic does not exist"
-          }
-        }
-      }
-    },
-    "/resource-quotas" : {
-      "get" : {
-        "tags" : [ "resource-quotas" ],
-        "summary" : "Get the default quota",
-        "description" : "",
-        "operationId" : "getDefaultResourceQuota",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "uniqueItems" : true,
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "resource-quotas" ],
-        "summary" : "Set the default quota",
-        "description" : "",
-        "operationId" : "setDefaultResourceQuota",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "uniqueItems" : true,
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          }
-        }
-      }
-    },
-    "/resource-quotas/{tenant}/{namespace}/{bundle}" : {
-      "get" : {
-        "tags" : [ "resource-quotas" ],
-        "summary" : "Get resource quota of a namespace bundle.",
-        "description" : "",
-        "operationId" : "getNamespaceBundleResourceQuota",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/ResourceQuota"
-            }
-          },
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "404" : {
-            "description" : "Namespace does not exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "resource-quotas" ],
-        "summary" : "Set resource quota on a namespace.",
-        "description" : "",
-        "operationId" : "setNamespaceBundleResourceQuota",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "resource-quotas" ],
-        "summary" : "Remove resource quota for a namespace.",
-        "description" : "",
-        "operationId" : "removeNamespaceBundleResourceQuota",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "bundle",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "Don't have admin permission"
-          },
-          "409" : {
-            "description" : "Concurrent modification"
-          }
-        }
-      }
-    },
-    "/schemas/{tenant}/{namespace}/{topic}/schema" : {
-      "get" : {
-        "tags" : [ "schemas" ],
-        "summary" : "Get the schema of a topic",
-        "description" : "",
-        "operationId" : "getSchema",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/GetSchemaResponse"
-            }
-          },
-          "307" : {
-            "description" : "Current broker doesn't serve the namespace of this topic"
-          },
-          "401" : {
-            "description" : "Client is not authorized or Don't have admin permission"
-          },
-          "403" : {
-            "description" : "Client is not authenticated"
-          },
-          "404" : {
-            "description" : "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"
-          },
-          "412" : {
-            "description" : "Failed to find the ownership for the topic"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "schemas" ],
-        "summary" : "Update the schema of a topic",
-        "description" : "",
-        "operationId" : "postSchema",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "in" : "body",
-          "name" : "body",
-          "description" : "A JSON value presenting a schema playload. An example of the expected schema can be found down here.",
-          "required" : false,
-          "schema" : {
-            "$ref" : "#/definitions/PostSchemaPayload"
-          },
-          "x-examples" : {
-            "application/json" : "{\"type\": \"STRING\", \"schema\": \"\", \"properties\": { \"key1\" : \"value1\" + } }"
-          }
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PostSchemaResponse"
-            }
-          },
-          "307" : {
-            "description" : "Current broker doesn't serve the namespace of this topic"
-          },
-          "401" : {
-            "description" : "Client is not authorized or Don't have admin permission"
-          },
-          "403" : {
-            "description" : "Client is not authenticated"
-          },
-          "404" : {
-            "description" : "Tenant or Namespace or Topic doesn't exist"
-          },
-          "412" : {
-            "description" : "Failed to find the ownership for the topic"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "schemas" ],
-        "summary" : "Delete the schema of a topic",
-        "description" : "",
-        "operationId" : "deleteSchema",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/DeleteSchemaResponse"
-            }
-          },
-          "307" : {
-            "description" : "Current broker doesn't serve the namespace of this topic"
-          },
-          "401" : {
-            "description" : "Client is not authorized or Don't have admin permission"
-          },
-          "403" : {
-            "description" : "Client is not authenticated"
-          },
-          "404" : {
-            "description" : "Tenant or Namespace or Topic doesn't exist"
-          },
-          "412" : {
-            "description" : "Failed to find the ownership for the topic"
-          }
-        }
-      }
-    },
-    "/schemas/{tenant}/{namespace}/{topic}/schema/{version}" : {
-      "get" : {
-        "tags" : [ "schemas" ],
-        "summary" : "Get the schema of a topic at a given version",
-        "description" : "",
-        "operationId" : "getSchema",
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "namespace",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "topic",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "version",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/GetSchemaResponse"
-            }
-          },
-          "307" : {
-            "description" : "Current broker doesn't serve the namespace of this topic"
-          },
-          "401" : {
-            "description" : "Client is not authorized or Don't have admin permission"
-          },
-          "403" : {
-            "description" : "Client is not authenticated"
-          },
-          "404" : {
-            "description" : "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"
-          },
-          "412" : {
-            "description" : "Failed to find the ownership for the topic"
-          }
-        }
-      }
-    },
-    "/tenants" : {
-      "get" : {
-        "tags" : [ "tenants" ],
-        "summary" : "Get the list of tenants.",
-        "description" : "",
-        "operationId" : "getTenants",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "type" : "string"
-              }
-            }
-          },
-          "403" : {
-            "description" : "The requester doesn't have admin permissions"
-          },
-          "404" : {
-            "description" : "Tenant doesn't exist"
-          }
-        }
-      }
-    },
-    "/tenants/{tenant}" : {
-      "get" : {
-        "tags" : [ "tenants" ],
-        "summary" : "Get the admin configuration for a given tenant.",
-        "description" : "",
-        "operationId" : "getTenantAdmin",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/TenantInfo"
-            }
-          },
-          "403" : {
-            "description" : "The requester doesn't have admin permissions"
-          },
-          "404" : {
-            "description" : "Tenant does not exist"
-          }
-        }
-      },
-      "post" : {
-        "tags" : [ "tenants" ],
-        "summary" : "Update the admins for a tenant.",
-        "description" : "This operation requires Pulsar super-user privileges.",
-        "operationId" : "updateTenant",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "The requester doesn't have admin permissions"
-          },
-          "404" : {
-            "description" : "Tenant does not exist"
-          },
-          "409" : {
-            "description" : "Tenant already exists"
-          }
-        }
-      },
-      "put" : {
-        "tags" : [ "tenants" ],
-        "summary" : "Create a new tenant.",
-        "description" : "This operation requires Pulsar super-user privileges.",
-        "operationId" : "createTenant",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "The requester doesn't have admin permissions"
-          },
-          "409" : {
-            "description" : "Tenant already exists"
-          },
-          "412" : {
-            "description" : "Tenant name is not valid"
-          }
-        }
-      },
-      "delete" : {
-        "tags" : [ "tenants" ],
-        "summary" : "Delete a tenant and all namespaces and topics under it.",
-        "description" : "",
-        "operationId" : "deleteTenant",
-        "consumes" : [ "application/json" ],
-        "produces" : [ "application/json" ],
-        "parameters" : [ {
-          "name" : "tenant",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        } ],
-        "responses" : {
-          "403" : {
-            "description" : "The requester doesn't have admin permissions"
-          },
-          "404" : {
-            "description" : "Tenant does not exist"
-          },
-          "409" : {
-            "description" : "The tenant still has active namespaces"
-          }
-        }
-      }
-    }
-  },
-  "definitions" : {
-    "AllocatorStats" : {
-      "type" : "object",
-      "properties" : {
-        "numDirectArenas" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "numHeapArenas" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "numThreadLocalCaches" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "normalCacheSize" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "smallCacheSize" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "tinyCacheSize" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "directArenas" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/PoolArenaStats"
-          }
-        },
-        "heapArenas" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/PoolArenaStats"
-          }
-        }
-      }
-    },
-    "AuthPolicies" : {
-      "type" : "object",
-      "properties" : {
-        "namespace_auth" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "array",
-            "uniqueItems" : true,
-            "items" : {
-              "type" : "string",
-              "enum" : [ "produce", "consume" ]
-            }
-          }
-        },
-        "destination_auth" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "object",
-            "additionalProperties" : {
-              "type" : "array",
-              "uniqueItems" : true,
-              "items" : {
-                "type" : "string",
-                "enum" : [ "produce", "consume" ]
-              }
-            }
-          }
-        }
-      }
-    },
-    "AutoFailoverPolicyData" : {
-      "type" : "object",
-      "properties" : {
-        "policy_type" : {
-          "type" : "string",
-          "enum" : [ "min_available" ]
-        },
-        "parameters" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "string"
-          }
-        }
-      }
-    },
-    "BacklogQuota" : {
-      "type" : "object",
-      "properties" : {
-        "limit" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "policy" : {
-          "type" : "string",
-          "enum" : [ "producer_request_hold", "producer_exception", "consumer_backlog_eviction" ]
-        }
-      }
-    },
-    "BookieInfo" : {
-      "type" : "object",
-      "properties" : {
-        "rack" : {
-          "type" : "string"
-        },
-        "hostname" : {
-          "type" : "string"
-        }
-      }
-    },
-    "BrokerNamespaceIsolationData" : {
-      "type" : "object",
-      "properties" : {
-        "brokerName" : {
-          "type" : "string"
-        },
-        "namespaceRegex" : {
-          "type" : "array",
-          "items" : {
-            "type" : "string"
-          }
-        }
-      }
-    },
-    "BundlesData" : {
-      "type" : "object",
-      "properties" : {
-        "boundaries" : {
-          "type" : "array",
-          "items" : {
-            "type" : "string"
-          }
-        },
-        "numBundles" : {
-          "type" : "integer",
-          "format" : "int32"
-        }
-      }
-    },
-    "ClusterData" : {
-      "type" : "object",
-      "properties" : {
-        "serviceUrl" : {
-          "type" : "string"
-        },
-        "serviceUrlTls" : {
-          "type" : "string"
-        },
-        "brokerServiceUrl" : {
-          "type" : "string"
-        },
-        "brokerServiceUrlTls" : {
-          "type" : "string"
-        },
-        "peerClusterNames" : {
-          "type" : "array",
-          "uniqueItems" : true,
-          "items" : {
-            "type" : "string"
-          }
-        }
-      }
-    },
-    "ConsumerStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateRedeliver" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "consumerName" : {
-          "type" : "string"
-        },
-        "availablePermits" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "unackedMessages" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "blockedConsumerOnUnackedMsgs" : {
-          "type" : "boolean"
-        },
-        "metadata" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "string"
-          }
-        },
-        "address" : {
-          "type" : "string"
-        },
-        "connectedSince" : {
-          "type" : "string"
-        },
-        "clientVersion" : {
-          "type" : "string"
-        }
-      }
-    },
-    "CursorDetails" : {
-      "type" : "object",
-      "properties" : {
-        "cursorBacklog" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "cursorLedgerId" : {
-          "type" : "integer",
-          "format" : "int64"
-        }
-      }
-    },
-    "CursorStats" : {
-      "type" : "object",
-      "properties" : {
-        "markDeletePosition" : {
-          "type" : "string"
-        },
-        "readPosition" : {
-          "type" : "string"
-        },
-        "waitingReadOp" : {
-          "type" : "boolean"
-        },
-        "pendingReadOps" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "messagesConsumedCounter" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "cursorLedger" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "cursorLedgerLastEntry" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "individuallyDeletedMessages" : {
-          "type" : "string"
-        },
-        "lastLedgerSwitchTimestamp" : {
-          "type" : "string"
-        },
-        "state" : {
-          "type" : "string"
-        },
-        "numberOfEntriesSinceFirstNotAckedMessage" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "totalNonContiguousDeletedMessagesRange" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "properties" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "integer",
-            "format" : "int64"
-          }
-        }
-      }
-    },
-    "DeleteSchemaResponse" : {
-      "type" : "object",
-      "properties" : {
-        "version" : {
-          "type" : "integer",
-          "format" : "int64"
-        }
-      }
-    },
-    "DispatchRate" : {
-      "type" : "object",
-      "properties" : {
-        "dispatchThrottlingRateInMsg" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "dispatchThrottlingRateInByte" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "ratePeriodInSecond" : {
-          "type" : "integer",
-          "format" : "int32"
-        }
-      }
-    },
-    "FailureDomain" : {
-      "type" : "object",
-      "properties" : {
-        "brokers" : {
-          "type" : "array",
-          "uniqueItems" : true,
-          "items" : {
-            "type" : "string"
-          }
-        }
-      }
-    },
-    "GetSchemaResponse" : {
-      "type" : "object",
-      "properties" : {
-        "version" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "type" : {
-          "type" : "string",
-          "enum" : [ "NONE", "STRING", "JSON", "PROTOBUF", "AVRO" ]
-        },
-        "timestamp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "data" : {
-          "type" : "string"
-        },
-        "properties" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "string"
-          }
-        }
-      }
-    },
-    "InternalConfigurationData" : {
-      "type" : "object",
-      "properties" : {
-        "zookeeperServers" : {
-          "type" : "string"
-        },
-        "configurationStoreServers" : {
-          "type" : "string"
-        },
-        "ledgersRootPath" : {
-          "type" : "string"
-        }
-      }
-    },
-    "LedgerDetails" : {
-      "type" : "object",
-      "properties" : {
-        "entries" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "timestamp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "size" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "ledgerId" : {
-          "type" : "integer",
-          "format" : "int64"
-        }
-      }
-    },
-    "LedgerInfo" : {
-      "type" : "object",
-      "properties" : {
-        "ledgerId" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "entries" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "size" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "offloaded" : {
-          "type" : "boolean"
-        }
-      }
-    },
-    "LoadReport" : {
-      "type" : "object",
-      "properties" : {
-        "name" : {
-          "type" : "string"
-        },
-        "brokerVersionString" : {
-          "type" : "string"
-        },
-        "webServiceUrl" : {
-          "type" : "string"
-        },
-        "webServiceUrlTls" : {
-          "type" : "string"
-        },
-        "pulsarServiceUrl" : {
-          "type" : "string"
-        },
-        "pulsarServiceUrlTls" : {
-          "type" : "string"
-        },
-        "persistentTopicsEnabled" : {
-          "type" : "boolean"
-        },
-        "nonPersistentTopicsEnabled" : {
-          "type" : "boolean"
-        },
-        "timestamp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "numTopics" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "numConsumers" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "numProducers" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "numBundles" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "systemResourceUsage" : {
-          "$ref" : "#/definitions/SystemResourceUsage"
-        },
-        "bundleStats" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/NamespaceBundleStats"
-          }
-        },
-        "bundleGains" : {
-          "type" : "array",
-          "uniqueItems" : true,
-          "items" : {
-            "type" : "string"
-          }
-        },
-        "bundleLosses" : {
-          "type" : "array",
-          "uniqueItems" : true,
-          "items" : {
-            "type" : "string"
-          }
-        },
-        "allocatedCPU" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "allocatedMemory" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "allocatedBandwidthIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "allocatedBandwidthOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "allocatedMsgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "allocatedMsgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "preAllocatedCPU" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "preAllocatedMemory" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "preAllocatedBandwidthIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "preAllocatedBandwidthOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "preAllocatedMsgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "preAllocatedMsgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "cpu" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        },
-        "directMemory" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        },
-        "bandwidthIn" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        },
-        "memory" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        },
-        "bandwidthOut" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        },
-        "lastUpdate" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "msgThroughputIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "overLoaded" : {
-          "type" : "boolean"
-        },
-        "loadReportType" : {
-          "type" : "string"
-        },
-        "underLoaded" : {
-          "type" : "boolean"
-        }
-      }
-    },
-    "LongRunningProcessStatus" : {
-      "type" : "object",
-      "properties" : {
-        "status" : {
-          "type" : "string",
-          "enum" : [ "NOT_RUN", "RUNNING", "SUCCESS", "ERROR" ]
-        },
-        "lastError" : {
-          "type" : "string"
-        }
-      }
-    },
-    "MessageId" : {
-      "type" : "object"
-    },
-    "MessageIdImpl" : {
-      "type" : "object",
-      "properties" : {
-        "ledgerId" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "entryId" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "partitionIndex" : {
-          "type" : "integer",
-          "format" : "int32"
-        }
-      }
-    },
-    "Metrics" : {
-      "type" : "object",
-      "properties" : {
-        "metrics" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "object"
-          }
-        },
-        "dimensions" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "string"
-          }
-        }
-      }
-    },
-    "NamespaceBundleStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "consumerCount" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "producerCount" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "topics" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "cacheSize" : {
-          "type" : "integer",
-          "format" : "int64"
-        }
-      }
-    },
-    "NamespaceIsolationData" : {
-      "type" : "object",
-      "properties" : {
-        "namespaces" : {
-          "type" : "array",
-          "items" : {
-            "type" : "string"
-          }
-        },
-        "primary" : {
-          "type" : "array",
-          "items" : {
-            "type" : "string"
-          }
-        },
-        "secondary" : {
-          "type" : "array",
-          "items" : {
-            "type" : "string"
-          }
-        },
-        "auto_failover_policy" : {
-          "$ref" : "#/definitions/AutoFailoverPolicyData"
-        }
-      }
-    },
-    "NamespaceOwnershipStatus" : {
-      "type" : "object",
-      "properties" : {
-        "broker_assignment" : {
-          "type" : "string",
-          "enum" : [ "primary", "secondary", "shared" ]
-        },
-        "is_controlled" : {
-          "type" : "boolean"
-        },
-        "is_active" : {
-          "type" : "boolean"
-        }
-      }
-    },
-    "NonPersistentPublisherStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "averageMsgSize" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "producerId" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "metadata" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "string"
-          }
-        },
-        "msgDropRate" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "address" : {
-          "type" : "string"
-        },
-        "connectedSince" : {
-          "type" : "string"
-        },
-        "clientVersion" : {
-          "type" : "string"
-        },
-        "producerName" : {
-          "type" : "string"
-        }
-      }
-    },
-    "NonPersistentReplicatorStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateExpired" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "replicationBacklog" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "connected" : {
-          "type" : "boolean"
-        },
-        "replicationDelayInSeconds" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "inboundConnection" : {
-          "type" : "string"
-        },
-        "inboundConnectedSince" : {
-          "type" : "string"
-        },
-        "outboundConnection" : {
-          "type" : "string"
-        },
-        "outboundConnectedSince" : {
-          "type" : "string"
-        },
-        "msgDropRate" : {
-          "type" : "number",
-          "format" : "double"
-        }
-      }
-    },
-    "NonPersistentSubscriptionStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateRedeliver" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgBacklog" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "blockedSubscriptionOnUnackedMsgs" : {
-          "type" : "boolean"
-        },
-        "unackedMessages" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "type" : {
-          "type" : "string",
-          "enum" : [ "Exclusive", "Shared", "Failover" ]
-        },
-        "activeConsumerName" : {
-          "type" : "string"
-        },
-        "msgRateExpired" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "consumers" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/ConsumerStats"
-          }
-        },
-        "msgDropRate" : {
-          "type" : "number",
-          "format" : "double"
-        }
-      }
-    },
-    "NonPersistentTopicStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "averageMsgSize" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "storageSize" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "publishers" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/NonPersistentPublisherStats"
-          }
-        },
-        "subscriptions" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/NonPersistentSubscriptionStats"
-          }
-        },
-        "replication" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/NonPersistentReplicatorStats"
-          }
-        },
-        "deduplicationStatus" : {
-          "type" : "string"
-        },
-        "msgDropRate" : {
-          "type" : "number",
-          "format" : "double"
-        }
-      }
-    },
-    "OffloadProcessStatus" : {
-      "type" : "object",
-      "properties" : {
-        "status" : {
-          "type" : "string",
-          "enum" : [ "NOT_RUN", "RUNNING", "SUCCESS", "ERROR" ]
-        },
-        "lastError" : {
-          "type" : "string"
-        },
-        "firstUnoffloadedMessage" : {
-          "$ref" : "#/definitions/MessageIdImpl"
-        }
-      }
-    },
-    "OutputStream" : {
-      "type" : "object"
-    },
-    "PartitionedTopicMetadata" : {
-      "type" : "object",
-      "properties" : {
-        "partitions" : {
-          "type" : "integer",
-          "format" : "int32"
-        }
-      }
-    },
-    "PartitionedTopicStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "averageMsgSize" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "storageSize" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "publishers" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/PublisherStats"
-          }
-        },
-        "subscriptions" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/SubscriptionStats"
-          }
-        },
-        "replication" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/ReplicatorStats"
-          }
-        },
-        "deduplicationStatus" : {
-          "type" : "string"
-        },
-        "metadata" : {
-          "$ref" : "#/definitions/PartitionedTopicMetadata"
-        },
-        "partitions" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/TopicStats"
-          }
-        }
-      }
-    },
-    "PendingBookieOpsStats" : {
-      "type" : "object",
-      "properties" : {
-        "dataLedgerOpenOp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "dataLedgerCloseOp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "dataLedgerCreateOp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "dataLedgerDeleteOp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "cursorLedgerOpenOp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "cursorLedgerCloseOp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "cursorLedgerCreateOp" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "cursorLedgerDeleteOp" : {
-          "type" : "integer",
-          "format" : "int64"
-        }
-      }
-    },
-    "PersistencePolicies" : {
-      "type" : "object",
-      "properties" : {
-        "bookkeeperEnsemble" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "bookkeeperWriteQuorum" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "bookkeeperAckQuorum" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "managedLedgerMaxMarkDeleteRate" : {
-          "type" : "number",
-          "format" : "double"
-        }
-      }
-    },
-    "PersistentOfflineTopicStats" : {
-      "type" : "object",
-      "properties" : {
-        "storageSize" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "totalMessages" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "messageBacklog" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "brokerName" : {
-          "type" : "string"
-        },
-        "topicName" : {
-          "type" : "string"
-        },
-        "dataLedgerDetails" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/LedgerDetails"
-          }
-        },
-        "cursorDetails" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/CursorDetails"
-          }
-        },
-        "statGeneratedAt" : {
-          "type" : "string",
-          "format" : "date-time"
-        }
-      }
-    },
-    "PersistentTopicInternalStats" : {
-      "type" : "object",
-      "properties" : {
-        "entriesAddedCounter" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numberOfEntries" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "totalSize" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "currentLedgerEntries" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "currentLedgerSize" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "lastLedgerCreatedTimestamp" : {
-          "type" : "string"
-        },
-        "lastLedgerCreationFailureTimestamp" : {
-          "type" : "string"
-        },
-        "waitingCursorsCount" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "pendingAddEntriesCount" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "lastConfirmedEntry" : {
-          "type" : "string"
-        },
-        "state" : {
-          "type" : "string"
-        },
-        "ledgers" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/LedgerInfo"
-          }
-        },
-        "cursors" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/CursorStats"
-          }
-        }
-      }
-    },
-    "Policies" : {
-      "type" : "object",
-      "properties" : {
-        "auth_policies" : {
-          "$ref" : "#/definitions/AuthPolicies"
-        },
-        "replication_clusters" : {
-          "type" : "array",
-          "uniqueItems" : true,
-          "items" : {
-            "type" : "string"
-          }
-        },
-        "bundles" : {
-          "$ref" : "#/definitions/BundlesData"
-        },
-        "backlog_quota_map" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/BacklogQuota"
-          }
-        },
-        "clusterDispatchRate" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/DispatchRate"
-          }
-        },
-        "subscriptionDispatchRate" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/DispatchRate"
-          }
-        },
-        "persistence" : {
-          "$ref" : "#/definitions/PersistencePolicies"
-        },
-        "deduplicationEnabled" : {
-          "type" : "boolean"
-        },
-        "latency_stats_sample_rate" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "integer",
-            "format" : "int32"
-          }
-        },
-        "message_ttl_in_seconds" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "retention_policies" : {
-          "$ref" : "#/definitions/RetentionPolicies"
-        },
-        "deleted" : {
-          "type" : "boolean"
-        },
-        "antiAffinityGroup" : {
-          "type" : "string"
-        },
-        "encryption_required" : {
-          "type" : "boolean"
-        },
-        "subscription_auth_mode" : {
-          "type" : "string",
-          "enum" : [ "None", "Prefix" ]
-        },
-        "max_producers_per_topic" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "max_consumers_per_topic" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "max_consumers_per_subscription" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "compaction_threshold" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "offload_threshold" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "offload_deletion_lag_ms" : {
-          "type" : "integer",
-          "format" : "int64"
-        }
-      }
-    },
-    "PoolArenaStats" : {
-      "type" : "object",
-      "properties" : {
-        "numTinySubpages" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "numSmallSubpages" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "numChunkLists" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "tinySubpages" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/PoolSubpageStats"
-          }
-        },
-        "smallSubpages" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/PoolSubpageStats"
-          }
-        },
-        "chunkLists" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/PoolChunkListStats"
-          }
-        },
-        "numAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numTinyAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numSmallAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numNormalAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numHugeAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numDeallocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numTinyDeallocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numSmallDeallocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numNormalDeallocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numHugeDeallocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numActiveAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numActiveTinyAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numActiveSmallAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numActiveNormalAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "numActiveHugeAllocations" : {
-          "type" : "integer",
-          "format" : "int64"
-        }
-      }
-    },
-    "PoolChunkListStats" : {
-      "type" : "object",
-      "properties" : {
-        "minUsage" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "maxUsage" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "chunks" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/PoolChunkStats"
-          }
-        }
-      }
-    },
-    "PoolChunkStats" : {
-      "type" : "object",
-      "properties" : {
-        "usage" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "chunkSize" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "freeBytes" : {
-          "type" : "integer",
-          "format" : "int32"
-        }
-      }
-    },
-    "PoolSubpageStats" : {
-      "type" : "object",
-      "properties" : {
-        "maxNumElements" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "numAvailable" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "elementSize" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "pageSize" : {
-          "type" : "integer",
-          "format" : "int32"
-        }
-      }
-    },
-    "PostSchemaPayload" : {
-      "type" : "object",
-      "properties" : {
-        "type" : {
-          "type" : "string"
-        },
-        "schema" : {
-          "type" : "string"
-        },
-        "properties" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "string"
-          }
-        }
-      }
-    },
-    "PostSchemaResponse" : {
-      "type" : "object",
-      "properties" : {
-        "version" : {
-          "$ref" : "#/definitions/SchemaVersion"
-        }
-      }
-    },
-    "PublisherStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "averageMsgSize" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "producerId" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "metadata" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "string"
-          }
-        },
-        "address" : {
-          "type" : "string"
-        },
-        "connectedSince" : {
-          "type" : "string"
-        },
-        "clientVersion" : {
-          "type" : "string"
-        },
-        "producerName" : {
-          "type" : "string"
-        }
-      }
-    },
-    "ReplicatorStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateExpired" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "replicationBacklog" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "connected" : {
-          "type" : "boolean"
-        },
-        "replicationDelayInSeconds" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "inboundConnection" : {
-          "type" : "string"
-        },
-        "inboundConnectedSince" : {
-          "type" : "string"
-        },
-        "outboundConnection" : {
-          "type" : "string"
-        },
-        "outboundConnectedSince" : {
-          "type" : "string"
-        }
-      }
-    },
-    "ResourceDescription" : {
-      "type" : "object",
-      "properties" : {
-        "usagePct" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "resourceUsage" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/ResourceUsage"
-          }
-        }
-      }
-    },
-    "ResourceQuota" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "bandwidthIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "bandwidthOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "memory" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "dynamic" : {
-          "type" : "boolean"
-        }
-      }
-    },
-    "ResourceUnit" : {
-      "type" : "object",
-      "properties" : {
-        "resourceId" : {
-          "type" : "string"
-        },
-        "availableResource" : {
-          "$ref" : "#/definitions/ResourceDescription"
-        }
-      }
-    },
-    "ResourceUsage" : {
-      "type" : "object",
-      "properties" : {
-        "usage" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "limit" : {
-          "type" : "number",
-          "format" : "double"
-        }
-      }
-    },
-    "RetentionPolicies" : {
-      "type" : "object",
-      "properties" : {
-        "retentionTimeInMinutes" : {
-          "type" : "integer",
-          "format" : "int32"
-        },
-        "retentionSizeInMB" : {
-          "type" : "integer",
-          "format" : "int64"
-        }
-      }
-    },
-    "SchemaVersion" : {
-      "type" : "object"
-    },
-    "SubscriptionStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateRedeliver" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgBacklog" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "blockedSubscriptionOnUnackedMsgs" : {
-          "type" : "boolean"
-        },
-        "unackedMessages" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "type" : {
-          "type" : "string",
-          "enum" : [ "Exclusive", "Shared", "Failover" ]
-        },
-        "activeConsumerName" : {
-          "type" : "string"
-        },
-        "msgRateExpired" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "consumers" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/ConsumerStats"
-          }
-        }
-      }
-    },
-    "SystemResourceUsage" : {
-      "type" : "object",
-      "properties" : {
-        "bandwidthIn" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        },
-        "bandwidthOut" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        },
-        "cpu" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        },
-        "memory" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        },
-        "directMemory" : {
-          "$ref" : "#/definitions/ResourceUsage"
-        }
-      }
-    },
-    "TenantInfo" : {
-      "type" : "object",
-      "properties" : {
-        "adminRoles" : {
-          "type" : "array",
-          "uniqueItems" : true,
-          "items" : {
-            "type" : "string"
-          }
-        },
-        "allowedClusters" : {
-          "type" : "array",
-          "uniqueItems" : true,
-          "items" : {
-            "type" : "string"
-          }
-        }
-      }
-    },
-    "TopicStats" : {
-      "type" : "object",
-      "properties" : {
-        "msgRateIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputIn" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgRateOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "msgThroughputOut" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "averageMsgSize" : {
-          "type" : "number",
-          "format" : "double"
-        },
-        "storageSize" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
-        "publishers" : {
-          "type" : "array",
-          "items" : {
-            "$ref" : "#/definitions/PublisherStats"
-          }
-        },
-        "subscriptions" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/SubscriptionStats"
-          }
-        },
-        "replication" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "$ref" : "#/definitions/ReplicatorStats"
-          }
-        },
-        "deduplicationStatus" : {
-          "type" : "string"
-        }
-      }
-    }
-  }
-}
\ No newline at end of file


[pulsar] 18/26: [pulsar-function] support bookie authentication from function-worker (#4088)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 4c2bb0cecad7ea9f537f5790d049ec5b3f2d994c
Author: Rajan Dhabalia <rd...@apache.org>
AuthorDate: Sun Apr 21 19:25:59 2019 -0700

    [pulsar-function] support bookie authentication from function-worker (#4088)
    
    ### Motivation
    Function worker uses bookie and zookeeper to store function's executable. However, function doesn't support authentication while connecting to bookie so, dbLog initialize fails when bookie requires auth&auth.
    
    ### Modification
    Add bk-client authentication param to worker-config.
---
 conf/functions_worker.yml                                 | 10 ++++++++++
 .../terraform-ansible/templates/functions_worker.yml      |  9 +++++++++
 .../java/org/apache/pulsar/functions/worker/Utils.java    |  8 ++++++++
 .../org/apache/pulsar/functions/worker/WorkerConfig.java  | 15 +++++++++++++++
 4 files changed, 42 insertions(+)

diff --git a/conf/functions_worker.yml b/conf/functions_worker.yml
index ea1456d..0266f2f 100644
--- a/conf/functions_worker.yml
+++ b/conf/functions_worker.yml
@@ -49,6 +49,16 @@ pulsarWebServiceUrl: http://localhost:8080
 # the authentication parameter to be used by the pulsar client used in worker service
 # clientAuthenticationParameters:
 
+# Bookie Authentication
+#
+# Authentication plugin to use when connecting to bookies
+# bookkeeperClientAuthenticationPlugin:
+# BookKeeper auth plugin implementatation specifics parameters name and values
+# bookkeeperClientAuthenticationParametersName:
+# Parameters for bookkeeper auth plugin
+# bookkeeperClientAuthenticationParameters:
+
+
 # pulsar topics used for function metadata management
 
 pulsarFunctionsNamespace: public/functions
diff --git a/deployment/terraform-ansible/templates/functions_worker.yml b/deployment/terraform-ansible/templates/functions_worker.yml
index 100d467..cb49ef8 100644
--- a/deployment/terraform-ansible/templates/functions_worker.yml
+++ b/deployment/terraform-ansible/templates/functions_worker.yml
@@ -36,6 +36,15 @@ downloadDirectory: /tmp/pulsar_functions
 processContainerFactory:
   logDirectory:
 
+# Bookie Authentication
+#
+# Authentication plugin to use when connecting to bookies
+# bookkeeperClientAuthenticationPlugin:
+# BookKeeper auth plugin implementatation specifics parameters name and values
+# bookkeeperClientAuthenticationParametersName:
+# Parameters for bookkeeper auth plugin
+# bookkeeperClientAuthenticationParameters:
+
 schedulerClassName: "org.apache.pulsar.functions.worker.scheduler.RoundRobinScheduler"
 functionAssignmentTopicName: "assignments"
 failureCheckFreqMs: 30000
diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/Utils.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/Utils.java
index 3c1fa4c..b6567a6 100644
--- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/Utils.java
+++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/Utils.java
@@ -149,6 +149,14 @@ public final class Utils {
                 .setUseDaemonThread(true);
         conf.setProperty("bkc.allowShadedLedgerManagerFactoryClass", true);
         conf.setProperty("bkc.shadedLedgerManagerFactoryClassPrefix", "dlshade.");
+        if (isNotBlank(workerConfig.getBookkeeperClientAuthenticationPlugin())) {
+            conf.setProperty("bkc.clientAuthProviderFactoryClass",
+                    workerConfig.getBookkeeperClientAuthenticationPlugin());
+            if (isNotBlank(workerConfig.getBookkeeperClientAuthenticationParametersName())) {
+                conf.setProperty("bkc." + workerConfig.getBookkeeperClientAuthenticationParametersName(),
+                        workerConfig.getBookkeeperClientAuthenticationParameters());
+            }
+        }
         return conf;
     }
 
diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/WorkerConfig.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/WorkerConfig.java
index 7404718..cd21a18 100644
--- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/WorkerConfig.java
+++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/WorkerConfig.java
@@ -206,6 +206,21 @@ public class WorkerConfig implements Serializable, PulsarConfiguration {
     )
     private String clientAuthenticationParameters;
     @FieldContext(
+        category = CATEGORY_CLIENT_SECURITY,
+        doc = "Authentication plugin to use when connecting to bookies"
+    )
+    private String bookkeeperClientAuthenticationPlugin;
+    @FieldContext(
+        category = CATEGORY_CLIENT_SECURITY,
+        doc = "BookKeeper auth plugin implementatation specifics parameters name and values"
+    )
+    private String bookkeeperClientAuthenticationParametersName;
+    @FieldContext(
+        category = CATEGORY_CLIENT_SECURITY,
+        doc = "Parameters for bookkeeper auth plugin"
+    )
+    private String bookkeeperClientAuthenticationParameters;
+    @FieldContext(
         category = CATEGORY_FUNC_METADATA_MNG,
         doc = "Frequency how often worker performs compaction on function-topics, in seconds"
     )


[pulsar] 19/26: Revert dup consumer and related code (#4142)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 164d237cbe597908aa8e9cda5a7b920a3b342777
Author: Ezequiel Lovelle <ez...@gmail.com>
AuthorDate: Mon Apr 29 15:06:14 2019 -0300

    Revert dup consumer and related code (#4142)
    
    * Revert "[cpp client] implement reference count for close() (#3863)"
    
    This reverts commit ee98e8b28ce1397c056757fe73115d21320ed883.
    
    * Revert Prevent dup consumers and refCount for cpp client
    
    Revert "[cpp client] Bugfix prevent dup consumer for same topic subscription"
    Revert "[Issue #3226][cpp client] Prevent dup consumers on same client cnx"
    
    This reverts commit fff02e2aa2064412dbae18b973eb2bb2abab25d8.
    This reverts commit 762e0ab9a52e2665a106766c211d45474adc833b.
    
    * Revert "Feature - implement reference count for ConsumerImpl (#3795)"
    
    This reverts commit ff4db8db12be2eb79d910e2b286306298f71320e.
    
    * Revert Prevent dup consumers and refCount for java client
    
    Revert "Prevent dup consumers on same client cnx with shared subscription"
    Revert "[java client] Bugfix prevent dup consumers for same topic subscribe"
    
    This reverts commit 231db030b9529737237721059b2a5b3044d4cab1.
    This reverts commit fb5dcd9a58524686f2f6208d41a1e82b5bbb8111.
---
 .../client/api/SimpleProducerConsumerTest.java     | 112 ---------------------
 pulsar-client-cpp/lib/ClientImpl.cc                |  13 ---
 pulsar-client-cpp/lib/ConsumerImpl.cc              |  12 ---
 pulsar-client-cpp/lib/ConsumerImpl.h               |   3 -
 pulsar-client-cpp/lib/ConsumerImplBase.h           |   1 -
 pulsar-client-cpp/tests/BasicEndToEndTest.cc       |  82 ---------------
 .../apache/pulsar/client/impl/ConsumerBase.java    |   9 --
 .../apache/pulsar/client/impl/ConsumerImpl.java    |   4 -
 .../pulsar/client/impl/PulsarClientImpl.java       |  19 ----
 .../org/apache/pulsar/storm/PulsarSpoutTest.java   |   7 +-
 10 files changed, 1 insertion(+), 261 deletions(-)

diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/SimpleProducerConsumerTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/SimpleProducerConsumerTest.java
index 2f5d764..4067bc3 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/SimpleProducerConsumerTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/SimpleProducerConsumerTest.java
@@ -2907,116 +2907,4 @@ public class SimpleProducerConsumerTest extends ProducerConsumerBase {
         assertEquals(latch.getCount(), 1);
         consumer.close();
     }
-
-    // Issue 3226: https://github.com/apache/pulsar/issues/3226
-    // Pull 3312: https://github.com/apache/pulsar/pull/3312
-    // Bugfix preventing duplicated consumers on same client cnx with shared subscription mode
-    @Test()
-    public void testPreventDupConsumersOnClientCnxForSingleSub() throws Exception {
-        final CompletableFuture<Void> future = new CompletableFuture<>();
-        final String topic = "persistent://my-property/my-ns/my-topic";
-        final String subName = "my-subscription";
-
-        Consumer<byte[]> consumer = pulsarClient.newConsumer().topic(topic)
-                .subscriptionName(subName)
-                .subscriptionType(SubscriptionType.Shared)
-                .subscribe();
-        Consumer<byte[]> consumerB = pulsarClient.newConsumer().topic(topic)
-                .subscriptionName(subName)
-                .subscriptionType(SubscriptionType.Shared)
-                .subscribe();
-
-        consumer.unsubscribeAsync().whenComplete((aVoid1, t1) -> {
-            if (t1 != null) {
-                future.completeExceptionally(t1);
-                return;
-            }
-
-            consumer.closeAsync().whenComplete((aVoid2, t2) -> {
-                if (t2 != null) {
-                    future.completeExceptionally(t2);
-                    return;
-                }
-                future.complete(null);
-            });
-        });
-
-        future.get(5, TimeUnit.SECONDS);
-        Assert.assertEquals(consumer, consumerB);
-        Assert.assertTrue(future.isDone());
-        Assert.assertFalse(future.isCompletedExceptionally());
-    }
-
-    @Test()
-    public void testPreventDupConsumersOnClientCnxForSingleSub_AllowDifferentTopics() throws Exception {
-        final CompletableFuture<Void> future = new CompletableFuture<>();
-        final String topic = "persistent://my-property/my-ns/my-topic";
-        final String subName = "my-subscription";
-
-        Consumer<byte[]> consumer = pulsarClient.newConsumer().topic(topic)
-                .subscriptionName(subName)
-                .subscriptionType(SubscriptionType.Shared)
-                .subscribe();
-        Consumer<byte[]> consumerB = pulsarClient.newConsumer().topic(topic)
-                .subscriptionName(subName)
-                .subscriptionType(SubscriptionType.Shared)
-                .subscribe();
-
-        // This consumer should be a newly subscription since is it from a different topic
-        // even though has the same subscription name.
-        Consumer<byte[]> consumerC = pulsarClient.newConsumer().topic(topic + "-different-topic")
-                .subscriptionName(subName)
-                .subscriptionType(SubscriptionType.Shared)
-                .subscribe();
-
-        consumer.unsubscribeAsync().whenComplete((aVoid1, t1) -> {
-            if (t1 != null) {
-                future.completeExceptionally(t1);
-                return;
-            }
-
-            consumer.closeAsync().whenComplete((aVoid2, t2) -> {
-                if (t2 != null) {
-                    future.completeExceptionally(t2);
-                    return;
-                }
-                future.complete(null);
-            });
-        });
-
-        future.get(5, TimeUnit.SECONDS);
-        Assert.assertEquals(consumer, consumerB);
-        Assert.assertTrue(future.isDone());
-        Assert.assertFalse(future.isCompletedExceptionally());
-
-        // consumerC is a newly created subscription.
-        Assert.assertNotEquals(consumer, consumerC);
-        Assert.assertTrue(consumerC.isConnected());
-        consumerC.close();
-    }
-
-    @Test
-    public void testRefCount_OnCloseConsumer() throws Exception {
-        final String topic = "persistent://my-property/my-ns/my-topic";
-        final String subName = "my-subscription";
-
-        Consumer<byte[]> consumerA = pulsarClient.newConsumer().topic(topic)
-                .subscriptionName(subName)
-                .subscriptionType(SubscriptionType.Shared)
-                .subscribe();
-        Consumer<byte[]> consumerB = pulsarClient.newConsumer().topic(topic)
-                .subscriptionName(subName)
-                .subscriptionType(SubscriptionType.Shared)
-                .subscribe();
-
-        Assert.assertEquals(consumerA, consumerB);
-
-        consumerA.close();
-        Assert.assertTrue(consumerA.isConnected());
-        Assert.assertTrue(consumerB.isConnected());
-
-        consumerB.close();
-        Assert.assertFalse(consumerA.isConnected());
-        Assert.assertFalse(consumerB.isConnected());
-    }
 }
diff --git a/pulsar-client-cpp/lib/ClientImpl.cc b/pulsar-client-cpp/lib/ClientImpl.cc
index e2c15e0..0e996cc 100644
--- a/pulsar-client-cpp/lib/ClientImpl.cc
+++ b/pulsar-client-cpp/lib/ClientImpl.cc
@@ -340,19 +340,6 @@ void ClientImpl::subscribeAsync(const std::string& topic, const std::string& con
             lock.unlock();
             callback(ResultInvalidConfiguration, Consumer());
             return;
-        } else if (conf.getConsumerType() == ConsumerShared) {
-            ConsumersList consumers(consumers_);
-            for (auto& weakPtr : consumers) {
-                ConsumerImplBasePtr consumer = weakPtr.lock();
-                if (consumer && consumer->getSubscriptionName() == consumerName &&
-                    consumer->getTopic() == topic && !consumer->isClosed()) {
-                    consumer->incrRefCount();
-                    lock.unlock();
-                    LOG_INFO("Reusing existing consumer instance for " << topic << " -- " << consumerName);
-                    callback(ResultOk, Consumer(consumer));
-                    return;
-                }
-            }
         }
     }
 
diff --git a/pulsar-client-cpp/lib/ConsumerImpl.cc b/pulsar-client-cpp/lib/ConsumerImpl.cc
index 3fce8d2..7f36e65 100644
--- a/pulsar-client-cpp/lib/ConsumerImpl.cc
+++ b/pulsar-client-cpp/lib/ConsumerImpl.cc
@@ -109,10 +109,6 @@ Future<Result, ConsumerImplBaseWeakPtr> ConsumerImpl::getConsumerCreatedFuture()
     return consumerCreatedPromise_.getFuture();
 }
 
-void ConsumerImpl::incrRefCount() { ++refCount_; }
-
-unsigned int ConsumerImpl::safeDecrRefCount() { return refCount_ > 0 ? refCount_-- : refCount_; }
-
 const std::string& ConsumerImpl::getSubscriptionName() const { return originalSubscriptionName_; }
 
 const std::string& ConsumerImpl::getTopic() const { return topic_; }
@@ -815,14 +811,6 @@ void ConsumerImpl::closeAsync(ResultCallback callback) {
         return;
     }
 
-    if (safeDecrRefCount() != 0) {
-        lock.unlock();
-        if (callback) {
-            callback(ResultOk);
-        }
-        return;
-    }
-
     ClientConnectionPtr cnx = getCnx().lock();
     if (!cnx) {
         lock.unlock();
diff --git a/pulsar-client-cpp/lib/ConsumerImpl.h b/pulsar-client-cpp/lib/ConsumerImpl.h
index 7e1066c..b5fe761 100644
--- a/pulsar-client-cpp/lib/ConsumerImpl.h
+++ b/pulsar-client-cpp/lib/ConsumerImpl.h
@@ -107,7 +107,6 @@ class ConsumerImpl : public ConsumerImplBase,
     virtual bool isReadCompacted();
     virtual void hasMessageAvailableAsync(HasMessageAvailableCallback callback);
     virtual void getLastMessageIdAsync(BrokerGetLastMessageIdCallback callback);
-    virtual void incrRefCount();
 
    protected:
     void connectionOpened(const ClientConnectionPtr& cnx);
@@ -141,7 +140,6 @@ class ConsumerImpl : public ConsumerImplBase,
     void statsCallback(Result, ResultCallback, proto::CommandAck_AckType);
     void notifyPendingReceivedCallback(Result result, Message& message, const ReceiveCallback& callback);
     void failPendingReceiveCallback();
-    unsigned int safeDecrRefCount();
 
     Optional<MessageId> clearReceiveQueue();
 
@@ -171,7 +169,6 @@ class ConsumerImpl : public ConsumerImplBase,
     UnAckedMessageTrackerScopedPtr unAckedMessageTrackerPtr_;
     BatchAcknowledgementTracker batchAcknowledgementTracker_;
     BrokerConsumerStatsImpl brokerConsumerStats_;
-    unsigned int refCount_ = 0;
 
     MessageCryptoPtr msgCrypto_;
     const bool readCompacted_;
diff --git a/pulsar-client-cpp/lib/ConsumerImplBase.h b/pulsar-client-cpp/lib/ConsumerImplBase.h
index e6be186..766b0a9 100644
--- a/pulsar-client-cpp/lib/ConsumerImplBase.h
+++ b/pulsar-client-cpp/lib/ConsumerImplBase.h
@@ -50,7 +50,6 @@ class ConsumerImplBase {
     virtual int getNumOfPrefetchedMessages() const = 0;
     virtual void getBrokerConsumerStatsAsync(BrokerConsumerStatsCallback callback) = 0;
     virtual void seekAsync(const MessageId& msgId, ResultCallback callback) = 0;
-    virtual void incrRefCount(){};
 };
 }  // namespace pulsar
 #endif  // PULSAR_CONSUMER_IMPL_BASE_HEADER
diff --git a/pulsar-client-cpp/tests/BasicEndToEndTest.cc b/pulsar-client-cpp/tests/BasicEndToEndTest.cc
index 3ee85db..8e4de24 100644
--- a/pulsar-client-cpp/tests/BasicEndToEndTest.cc
+++ b/pulsar-client-cpp/tests/BasicEndToEndTest.cc
@@ -2794,85 +2794,3 @@ TEST(BasicEndToEndTest, testPartitionedReceiveAsyncFailedConsumer) {
     ASSERT_EQ(count, 0);
     client.shutdown();
 }
-
-TEST(BasicEndToEndTest, testPreventDupConsumersOnSharedMode) {
-    ClientConfiguration config;
-    Client client(lookupUrl);
-    std::string subsName = "my-only-sub";
-    std::string topicName = "persistent://public/default/test-prevent-dup-consumers";
-    ConsumerConfiguration consumerConf;
-    consumerConf.setConsumerType(ConsumerShared);
-
-    Consumer consumerA;
-    Result resultA = client.subscribe(topicName, subsName, consumerConf, consumerA);
-    ASSERT_EQ(ResultOk, resultA);
-    ASSERT_EQ(consumerA.getSubscriptionName(), subsName);
-
-    Consumer consumerB;
-    Result resultB = client.subscribe(topicName, subsName, consumerConf, consumerB);
-    ASSERT_EQ(ResultOk, resultB);
-    ASSERT_EQ(consumerB.getSubscriptionName(), subsName);
-
-    // Since this is a shared consumer over same client cnx
-    // closing consumerA should result in consumerB also being closed.
-    ASSERT_EQ(ResultOk, consumerA.close());
-    ASSERT_EQ(ResultOk, consumerB.close());
-    ASSERT_EQ(ResultAlreadyClosed, consumerA.close());
-    ASSERT_EQ(ResultAlreadyClosed, consumerB.close());
-}
-
-TEST(BasicEndToEndTest, testDupConsumersOnSharedModeNotThrowsExcOnUnsubscribe) {
-    ClientConfiguration config;
-    Client client(lookupUrl);
-    std::string subsName = "my-only-sub";
-    std::string topicName =
-        "persistent://public/default/testDupConsumersOnSharedModeNotThrowsExcOnUnsubscribe";
-    ConsumerConfiguration consumerConf;
-    consumerConf.setConsumerType(ConsumerShared);
-
-    Consumer consumerA;
-    Result resultA = client.subscribe(topicName, subsName, consumerConf, consumerA);
-    ASSERT_EQ(ResultOk, resultA);
-    ASSERT_EQ(consumerA.getSubscriptionName(), subsName);
-
-    Consumer consumerB;
-    Result resultB = client.subscribe(topicName, subsName, consumerConf, consumerB);
-    ASSERT_EQ(ResultOk, resultB);
-    ASSERT_EQ(consumerB.getSubscriptionName(), subsName);
-
-    ASSERT_EQ(ResultOk, consumerA.unsubscribe());
-    // If dup consumers are allowed BrokerMetadataError will be the result of close()
-    ASSERT_EQ(ResultAlreadyClosed, consumerA.close());
-}
-
-TEST(BasicEndToEndTest, testPreventDupConsumersAllowSameSubForDifferentTopics) {
-    ClientConfiguration config;
-    Client client(lookupUrl);
-    std::string subsName = "my-only-sub";
-    std::string topicName =
-        "persistent://public/default/testPreventDupConsumersAllowSameSubForDifferentTopics";
-    ConsumerConfiguration consumerConf;
-    consumerConf.setConsumerType(ConsumerShared);
-
-    Consumer consumerA;
-    Result resultA = client.subscribe(topicName, subsName, consumerConf, consumerA);
-    ASSERT_EQ(ResultOk, resultA);
-    ASSERT_EQ(consumerA.getSubscriptionName(), subsName);
-
-    Consumer consumerB;
-    Result resultB = client.subscribe(topicName, subsName, consumerConf, consumerB);
-    ASSERT_EQ(ResultOk, resultB);
-    ASSERT_EQ(consumerB.getSubscriptionName(), subsName);
-
-    Consumer consumerC;
-    Result resultC = client.subscribe(topicName + "-different-topic", subsName, consumerConf, consumerC);
-    ASSERT_EQ(ResultOk, resultB);
-    ASSERT_EQ(consumerB.getSubscriptionName(), subsName);
-    ASSERT_EQ(ResultOk, consumerA.close());
-    ASSERT_EQ(ResultOk, consumerB.close());
-    ASSERT_EQ(ResultAlreadyClosed, consumerA.close());
-    ASSERT_EQ(ResultAlreadyClosed, consumerB.close());
-
-    // consumer C should be a different instance from A and B and should be with open state.
-    ASSERT_EQ(ResultOk, consumerC.close());
-}
diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java
index 7132ed0..71fc310 100644
--- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java
+++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java
@@ -61,7 +61,6 @@ public abstract class ConsumerBase<T> extends HandlerState implements Consumer<T
     protected int maxReceiverQueueSize;
     protected final Schema<T> schema;
     protected final ConsumerInterceptors<T> interceptors;
-    private int refCount = 0;
 
     protected ConsumerBase(PulsarClientImpl client, String topic, ConsumerConfigurationData<T> conf,
                            int receiverQueueSize, ExecutorService listenerExecutor,
@@ -380,12 +379,4 @@ public abstract class ConsumerBase<T> extends HandlerState implements Consumer<T
             interceptors.onAcknowledgeCumulative(this, messageId, exception);
         }
     }
-
-    protected synchronized void incrRefCount() {
-        ++refCount;
-    }
-
-    protected synchronized boolean shouldTearDown() {
-        return refCount > 0 ? refCount-- == 0 : refCount == 0;
-    }
 }
diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java
index 266f483..4ecadfe 100644
--- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java
+++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java
@@ -681,10 +681,6 @@ public class ConsumerImpl<T> extends ConsumerBase<T> implements ConnectionHandle
 
     @Override
     public CompletableFuture<Void> closeAsync() {
-        if (!shouldTearDown()) {
-            return CompletableFuture.completedFuture(null);
-        }
-
         if (getState() == State.Closing || getState() == State.Closed) {
             unAckedMessageTracker.close();
             if (possibleSendToDeadLetterTopicMessages != null) {
diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java
index aa6c671..a2027ad 100644
--- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java
+++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java
@@ -311,11 +311,6 @@ public class PulsarClientImpl implements PulsarClient {
     }
 
     private <T> CompletableFuture<Consumer<T>> doSingleTopicSubscribeAsync(ConsumerConfigurationData<T> conf, Schema<T> schema, ConsumerInterceptors<T> interceptors) {
-        Optional<ConsumerBase<T>> subscriber = subscriptionExist(conf);
-        if (subscriber.isPresent()) {
-            return CompletableFuture.completedFuture(subscriber.get());
-        }
-
         CompletableFuture<Consumer<T>> consumerSubscribedFuture = new CompletableFuture<>();
 
         String topic = conf.getSingleTopic();
@@ -674,20 +669,6 @@ public class PulsarClientImpl implements PulsarClient {
         });
     }
 
-    @SuppressWarnings("unchecked")
-    private <T> Optional<ConsumerBase<T>> subscriptionExist(ConsumerConfigurationData<?> conf) {
-        synchronized (consumers) {
-            Optional<ConsumerBase<?>> subscriber = consumers.keySet().stream()
-                    .filter(c -> c.getSubType().equals(PulsarApi.CommandSubscribe.SubType.Shared))
-                    .filter(c -> conf.getTopicNames().contains(c.getTopic()))
-                    .filter(c -> c.getSubscription().equals(conf.getSubscriptionName()))
-                    .filter(Consumer::isConnected)
-                    .findFirst();
-            subscriber.ifPresent(ConsumerBase::incrRefCount);
-            return subscriber.map(ConsumerBase.class::cast);
-        }
-    }
-
     private static EventLoopGroup getEventLoopGroup(ClientConfigurationData conf) {
         ThreadFactory threadFactory = getThreadFactory("pulsar-client-io");
         return EventLoopUtil.newEventLoopGroup(conf.getNumIoThreads(), threadFactory);
diff --git a/tests/pulsar-storm-test/src/test/java/org/apache/pulsar/storm/PulsarSpoutTest.java b/tests/pulsar-storm-test/src/test/java/org/apache/pulsar/storm/PulsarSpoutTest.java
index 877c927..d316be3 100644
--- a/tests/pulsar-storm-test/src/test/java/org/apache/pulsar/storm/PulsarSpoutTest.java
+++ b/tests/pulsar-storm-test/src/test/java/org/apache/pulsar/storm/PulsarSpoutTest.java
@@ -301,17 +301,12 @@ public class PulsarSpoutTest extends ProducerConsumerBase {
         otherSpout.open(Maps.newHashMap(), context, collector);
 
         topicStats = admin.topics().getStats(topic);
-        Assert.assertEquals(topicStats.subscriptions.get(subscriptionName).consumers.size(), 1);
+        Assert.assertEquals(topicStats.subscriptions.get(subscriptionName).consumers.size(), 2);
 
         otherSpout.close();
 
         topicStats = admin.topics().getStats(topic);
         Assert.assertEquals(topicStats.subscriptions.get(subscriptionName).consumers.size(), 1);
-
-        otherSpout.close();
-
-        topicStats = admin.topics().getStats(topic);
-        Assert.assertEquals(topicStats.subscriptions.get(subscriptionName).consumers.size(), 0);
     }
 
     @Test


[pulsar] 16/26: For functions metrics in prometheus also remove TYPE (#4081)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit f497feb1054c1a211672e90f5f3196405db8325e
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Sat Apr 20 17:44:21 2019 -0700

    For functions metrics in prometheus also remove TYPE (#4081)
---
 .../instance/stats/PrometheusTextFormat.java        | 21 ---------------------
 1 file changed, 21 deletions(-)

diff --git a/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/PrometheusTextFormat.java b/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/PrometheusTextFormat.java
index 52d756d..f7a205c 100644
--- a/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/PrometheusTextFormat.java
+++ b/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/stats/PrometheusTextFormat.java
@@ -37,12 +37,6 @@ public class PrometheusTextFormat {
          */
         while (mfs.hasMoreElements()) {
             Collector.MetricFamilySamples metricFamilySamples = mfs.nextElement();
-            writer.write("# TYPE ");
-            writer.write(metricFamilySamples.name);
-            writer.write(' ');
-            writer.write(typeString(metricFamilySamples.type));
-            writer.write('\n');
-
             for (Collector.MetricFamilySamples.Sample sample : metricFamilySamples.samples) {
                 writer.write(sample.name);
                 if (sample.labelNames.size() > 0) {
@@ -66,21 +60,6 @@ public class PrometheusTextFormat {
         }
     }
 
-    private static String typeString(Collector.Type t) {
-        switch (t) {
-        case GAUGE:
-            return "gauge";
-        case COUNTER:
-            return "counter";
-        case SUMMARY:
-            return "summary";
-        case HISTOGRAM:
-            return "histogram";
-        default:
-            return "untyped";
-        }
-    }
-
     private static void writeEscapedLabelValue(Writer writer, String s) throws IOException {
         for (int i = 0; i < s.length(); i++) {
             char c = s.charAt(i);


[pulsar] 06/26: Handle subrecords in JsonSchema encoding (#4023)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit ab7887a6e48784df363e2aae8f83f6325a3a8565
Author: Yoann Ciabaud <yc...@users.noreply.github.com>
AuthorDate: Fri Apr 12 02:09:21 2019 +0200

    Handle subrecords in JsonSchema encoding (#4023)
---
 pulsar-client-cpp/python/pulsar/schema/schema.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pulsar-client-cpp/python/pulsar/schema/schema.py b/pulsar-client-cpp/python/pulsar/schema/schema.py
index 91250a8..260d7b0 100644
--- a/pulsar-client-cpp/python/pulsar/schema/schema.py
+++ b/pulsar-client-cpp/python/pulsar/schema/schema.py
@@ -80,7 +80,7 @@ class JsonSchema(Schema):
 
     def encode(self, obj):
         self._validate_object_type(obj)
-        return json.dumps(obj.__dict__, indent=True).encode('utf-8')
+        return json.dumps(obj.__dict__, default=lambda o: o.__dict__, indent=True).encode('utf-8')
 
     def decode(self, data):
         return self._record_cls(**json.loads(data))


[pulsar] 23/26: Validate admin operation on topic with authoritative parameter (#4270)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 389bd1fd74c01a5793b79d86e4d6eb82248d40ac
Author: Like <ke...@outlook.com>
AuthorDate: Thu May 16 05:20:55 2019 +0800

    Validate admin operation on topic with authoritative parameter (#4270)
---
 .../java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java
index 962c0dc..b29eb9c 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java
@@ -309,7 +309,7 @@ public class PersistentTopicsBase extends AdminResource {
     }
 
     protected void internalDeleteTopicForcefully(boolean authoritative) {
-        validateAdminOperationOnTopic(true);
+        validateAdminOperationOnTopic(authoritative);
         Topic topic = getTopicReference(topicName);
         try {
             topic.deleteForcefully().get();


[pulsar] 01/26: [pulsar-broker] add producer/consumer id in error-logging (#3961)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 6a8d8389d8d37ca5bdc9fa379220206e431904e7
Author: Rajan Dhabalia <rd...@apache.org>
AuthorDate: Sun Apr 7 22:23:51 2019 -0700

    [pulsar-broker] add producer/consumer id in error-logging (#3961)
    
    ### Motivation
    
    Log Producer/Consumer Id when broker logs "Producer/consumer is already connected" to help in debugging when client is keep failing to create producer and broker is keep logging  the same error.
---
 .../java/org/apache/pulsar/broker/service/ServerCnx.java | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/ServerCnx.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/ServerCnx.java
index e5bbf51..046567f 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/ServerCnx.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/ServerCnx.java
@@ -567,8 +567,8 @@ public class ServerCnx extends PulsarHandler {
                         if (existingConsumerFuture != null) {
                             if (existingConsumerFuture.isDone() && !existingConsumerFuture.isCompletedExceptionally()) {
                                 Consumer consumer = existingConsumerFuture.getNow(null);
-                                log.info("[{}] Consumer with the same id is already created: {}", remoteAddress,
-                                        consumer);
+                                log.info("[{}] Consumer with the same id {} is already created: {}", remoteAddress,
+                                        consumerId, consumer);
                                 ctx.writeAndFlush(Commands.newSuccess(requestId));
                                 return null;
                             } else {
@@ -577,8 +577,8 @@ public class ServerCnx extends PulsarHandler {
                                 // client timeout is lower the broker timeouts. We need to wait until the previous
                                 // consumer
                                 // creation request either complete or fails.
-                                log.warn("[{}][{}][{}] Consumer is already present on the connection", remoteAddress,
-                                        topicName, subscriptionName);
+                                log.warn("[{}][{}][{}] Consumer with id {} is already present on the connection", remoteAddress,
+                                        topicName, subscriptionName, consumerId);
                                 ServerError error = !existingConsumerFuture.isDone() ? ServerError.ServiceNotReady
                                         : getErrorCode(existingConsumerFuture);
                                 ctx.writeAndFlush(Commands.newError(requestId, error,
@@ -755,8 +755,8 @@ public class ServerCnx extends PulsarHandler {
                         if (existingProducerFuture != null) {
                             if (existingProducerFuture.isDone() && !existingProducerFuture.isCompletedExceptionally()) {
                                 Producer producer = existingProducerFuture.getNow(null);
-                                log.info("[{}] Producer with the same id is already created: {}", remoteAddress,
-                                        producer);
+                                log.info("[{}] Producer with the same id {} is already created: {}", remoteAddress,
+                                        producerId, producer);
                                 ctx.writeAndFlush(Commands.newProducerSuccess(requestId, producer.getProducerName(),
                                     producer.getSchemaVersion()));
                                 return null;
@@ -770,8 +770,8 @@ public class ServerCnx extends PulsarHandler {
                                 // either complete or fails.
                                 ServerError error = !existingProducerFuture.isDone() ? ServerError.ServiceNotReady
                                         : getErrorCode(existingProducerFuture);
-                                log.warn("[{}][{}] Producer is already present on the connection", remoteAddress,
-                                        topicName);
+                                log.warn("[{}][{}] Producer with id {} is already present on the connection", remoteAddress,
+                                        producerId, topicName);
                                 ctx.writeAndFlush(Commands.newError(requestId, error,
                                         "Producer is already present on the connection"));
                                 return null;


[pulsar] 12/26: Upgrade athenz libraries (#4056)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 553d568d7bc6079f921878405224756f6dc9394b
Author: massakam <ma...@yahoo-corp.jp>
AuthorDate: Wed Apr 17 08:31:33 2019 +0900

    Upgrade athenz libraries (#4056)
---
 pom.xml                                            |  2 +-
 .../client/impl/auth/AuthenticationAthenz.java     | 10 +++++++++
 .../client/impl/auth/AuthenticationAthenzTest.java | 24 ++++++++++++++++++++++
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 006cfa1..7c3ccee 100644
--- a/pom.xml
+++ b/pom.xml
@@ -148,7 +148,7 @@ flexible messaging model and an intuitive client API.</description>
     <storm.version>1.0.5</storm.version>
     <jetty.version>9.4.12.v20180830</jetty.version>
     <jersey.version>2.27</jersey.version>
-    <athenz.version>1.7.17</athenz.version>
+    <athenz.version>1.8.17</athenz.version>
     <prometheus.version>0.5.0</prometheus.version>
     <aspectj.version>1.9.2</aspectj.version>
     <rocksdb.version>5.13.3</rocksdb.version>
diff --git a/pulsar-client-auth-athenz/src/main/java/org/apache/pulsar/client/impl/auth/AuthenticationAthenz.java b/pulsar-client-auth-athenz/src/main/java/org/apache/pulsar/client/impl/auth/AuthenticationAthenz.java
index e814ae6..3e0aef3 100644
--- a/pulsar-client-auth-athenz/src/main/java/org/apache/pulsar/client/impl/auth/AuthenticationAthenz.java
+++ b/pulsar-client-auth-athenz/src/main/java/org/apache/pulsar/client/impl/auth/AuthenticationAthenz.java
@@ -59,6 +59,10 @@ public class AuthenticationAthenz implements Authentication, EncodedAuthenticati
     private String providerDomain;
     private PrivateKey privateKey;
     private String keyId = "0";
+    // If auto prefetching is enabled, application will not complete until the static method
+    // ZTSClient.cancelPrefetch() is called.
+    // cf. https://github.com/yahoo/athenz/issues/544
+    private boolean autoPrefetchEnabled = false;
     private long cachedRoleTokenTimestamp;
     private String roleToken;
     private final int minValidity = 2 * 60 * 60; // athenz will only give this token if it's at least valid for 2hrs
@@ -136,6 +140,8 @@ public class AuthenticationAthenz implements Authentication, EncodedAuthenticati
         }
 
         this.keyId = authParams.getOrDefault("keyId", "0");
+        this.autoPrefetchEnabled = Boolean.valueOf(authParams.getOrDefault("autoPrefetchEnabled", "false"));
+
         if (authParams.containsKey("athenzConfPath")) {
             System.setProperty("athenz.athenz_conf", authParams.get("athenzConfPath"));
         }
@@ -156,6 +162,9 @@ public class AuthenticationAthenz implements Authentication, EncodedAuthenticati
 
     @Override
     public void close() throws IOException {
+        if (ztsClient != null) {
+            ztsClient.close();
+        }
     }
 
     private ZTSClient getZtsClient() {
@@ -163,6 +172,7 @@ public class AuthenticationAthenz implements Authentication, EncodedAuthenticati
             ServiceIdentityProvider siaProvider = new SimpleServiceIdentityProvider(tenantDomain, tenantService,
                     privateKey, keyId);
             ztsClient = new ZTSClient(ztsUrl, tenantDomain, tenantService, siaProvider);
+            ztsClient.setPrefetchAutoEnable(this.autoPrefetchEnabled);
         }
         return ztsClient;
     }
diff --git a/pulsar-client-auth-athenz/src/test/java/org/apache/pulsar/client/impl/auth/AuthenticationAthenzTest.java b/pulsar-client-auth-athenz/src/test/java/org/apache/pulsar/client/impl/auth/AuthenticationAthenzTest.java
index 36df7f1..4419c1b 100644
--- a/pulsar-client-auth-athenz/src/test/java/org/apache/pulsar/client/impl/auth/AuthenticationAthenzTest.java
+++ b/pulsar-client-auth-athenz/src/test/java/org/apache/pulsar/client/impl/auth/AuthenticationAthenzTest.java
@@ -19,6 +19,7 @@
 package org.apache.pulsar.client.impl.auth;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 import org.testng.annotations.Test;
 import org.apache.pulsar.client.impl.auth.AuthenticationAthenz;
@@ -171,4 +172,27 @@ public class AuthenticationAthenzTest {
             Assert.fail();
         }
     }
+
+    @Test
+    public void testAutoPrefetchEnabled() throws Exception {
+        Field field = auth.getClass().getDeclaredField("autoPrefetchEnabled");
+        field.setAccessible(true);
+        assertFalse((boolean) field.get(auth));
+
+        String paramsStr = new String(Files.readAllBytes(Paths.get("./src/test/resources/authParams.json")));
+        ObjectMapper jsonMapper = ObjectMapperFactory.create();
+        Map<String, String> authParamsMap = jsonMapper.readValue(paramsStr, new TypeReference<HashMap<String, String>>() { });
+
+        authParamsMap.put("autoPrefetchEnabled", "true");
+        AuthenticationAthenz auth1 = new AuthenticationAthenz();
+        auth1.configure(jsonMapper.writeValueAsString(authParamsMap));
+        assertTrue((boolean) field.get(auth1));
+        auth1.close();
+
+        authParamsMap.put("autoPrefetchEnabled", "false");
+        AuthenticationAthenz auth2 = new AuthenticationAthenz();
+        auth2.configure(jsonMapper.writeValueAsString(authParamsMap));
+        assertFalse((boolean) field.get(auth2));
+        auth2.close();
+    }
 }


[pulsar] 15/26: [client] Set actual topic name to partitioned consumer (#4064)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 487eaff759dd687c91f821907e83974ea4c3b7aa
Author: massakam <ma...@yahoo-corp.jp>
AuthorDate: Thu Apr 18 07:09:50 2019 +0900

    [client] Set actual topic name to partitioned consumer (#4064)
    
    * Set actual topic name to partitioned consumer
    
    * Change dummy topic name prefix
---
 .../client/api/PartitionedProducerConsumerTest.java |  1 +
 .../client/impl/PatternTopicsConsumerImplTest.java  |  1 +
 .../pulsar/client/impl/TopicsConsumerImplTest.java  |  1 +
 .../pulsar/client/impl/MultiTopicsConsumerImpl.java | 21 ++++++++++++++++-----
 4 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/PartitionedProducerConsumerTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/PartitionedProducerConsumerTest.java
index 55952b7..0a88963 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/PartitionedProducerConsumerTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/PartitionedProducerConsumerTest.java
@@ -87,6 +87,7 @@ public class PartitionedProducerConsumerTest extends ProducerConsumerBase {
 
         Consumer<byte[]> consumer = pulsarClient.newConsumer().topic(topicName.toString())
                 .subscriptionName("my-partitioned-subscriber").subscribe();
+        assertEquals(consumer.getTopic(), topicName.toString());
 
         for (int i = 0; i < 10; i++) {
             String message = "my-message-" + i;
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/client/impl/PatternTopicsConsumerImplTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/client/impl/PatternTopicsConsumerImplTest.java
index 9a09ef7..4228fdb 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/client/impl/PatternTopicsConsumerImplTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/client/impl/PatternTopicsConsumerImplTest.java
@@ -172,6 +172,7 @@ public class PatternTopicsConsumerImplTest extends ProducerConsumerBase {
             .ackTimeout(ackTimeOutMillis, TimeUnit.MILLISECONDS)
             .receiverQueueSize(4)
             .subscribe();
+        assertTrue(consumer.getTopic().startsWith(PatternMultiTopicsConsumerImpl.DUMMY_TOPIC_NAME_PREFIX));
 
         // 4. verify consumer get methods, to get right number of partitions and topics.
         assertSame(pattern, ((PatternMultiTopicsConsumerImpl<?>) consumer).getPattern());
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/client/impl/TopicsConsumerImplTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/client/impl/TopicsConsumerImplTest.java
index fc46586..69f1c74 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/client/impl/TopicsConsumerImplTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/client/impl/TopicsConsumerImplTest.java
@@ -121,6 +121,7 @@ public class TopicsConsumerImplTest extends ProducerConsumerBase {
             .receiverQueueSize(4)
             .subscribe();
         assertTrue(consumer instanceof MultiTopicsConsumerImpl);
+        assertTrue(consumer.getTopic().startsWith(MultiTopicsConsumerImpl.DUMMY_TOPIC_NAME_PREFIX));
 
         List<String> topics = ((MultiTopicsConsumerImpl<byte[]>) consumer).getPartitionedTopics();
         List<ConsumerImpl<byte[]>> consumers = ((MultiTopicsConsumerImpl) consumer).getConsumers();
diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/MultiTopicsConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/MultiTopicsConsumerImpl.java
index 39c0511..df20e2a 100644
--- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/MultiTopicsConsumerImpl.java
+++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/MultiTopicsConsumerImpl.java
@@ -63,6 +63,8 @@ import org.slf4j.LoggerFactory;
 
 public class MultiTopicsConsumerImpl<T> extends ConsumerBase<T> {
 
+    public static final String DUMMY_TOPIC_NAME_PREFIX = "MultiTopicsConsumer-";
+
     // All topics should be in same namespace
     protected NamespaceName namespaceName;
 
@@ -93,10 +95,18 @@ public class MultiTopicsConsumerImpl<T> extends ConsumerBase<T> {
     private final UnAckedMessageTracker unAckedMessageTracker;
     private final ConsumerConfigurationData<T> internalConfig;
 
-    MultiTopicsConsumerImpl(PulsarClientImpl client, ConsumerConfigurationData<T> conf, ExecutorService listenerExecutor,
-                            CompletableFuture<Consumer<T>> subscribeFuture, Schema<T> schema, ConsumerInterceptors<T> interceptors) {
-        super(client, "TopicsConsumerFakeTopicName" + ConsumerName.generateRandomName(), conf,
-                Math.max(2, conf.getReceiverQueueSize()), listenerExecutor, subscribeFuture, schema, interceptors);
+    MultiTopicsConsumerImpl(PulsarClientImpl client, ConsumerConfigurationData<T> conf,
+            ExecutorService listenerExecutor, CompletableFuture<Consumer<T>> subscribeFuture, Schema<T> schema,
+            ConsumerInterceptors<T> interceptors) {
+        this(client, DUMMY_TOPIC_NAME_PREFIX + ConsumerName.generateRandomName(), conf, listenerExecutor,
+                subscribeFuture, schema, interceptors);
+    }
+
+    MultiTopicsConsumerImpl(PulsarClientImpl client, String singleTopic, ConsumerConfigurationData<T> conf,
+            ExecutorService listenerExecutor, CompletableFuture<Consumer<T>> subscribeFuture, Schema<T> schema,
+            ConsumerInterceptors<T> interceptors) {
+        super(client, singleTopic, conf, Math.max(2, conf.getReceiverQueueSize()), listenerExecutor, subscribeFuture,
+                schema, interceptors);
 
         checkArgument(conf.getReceiverQueueSize() > 0,
             "Receiver queue size needs to be greater than 0 for Topics Consumer");
@@ -663,7 +673,8 @@ public class MultiTopicsConsumerImpl<T> extends ConsumerBase<T> {
         cloneConf.getTopicNames().remove(topicName);
 
         CompletableFuture<Consumer> future = new CompletableFuture<>();
-        MultiTopicsConsumerImpl consumer = new MultiTopicsConsumerImpl(client, cloneConf, listenerExecutor, future, schema, interceptors);
+        MultiTopicsConsumerImpl consumer = new MultiTopicsConsumerImpl(client, topicName, cloneConf, listenerExecutor,
+                future, schema, interceptors);
 
         future.thenCompose(c -> ((MultiTopicsConsumerImpl)c).subscribeAsync(topicName, numPartitions))
             .thenRun(()-> subscribeFuture.complete(consumer))


[pulsar] 22/26: [pulsar-function] fix broken backward compatibility with v1-namespace while registering function (#4224)

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 20695e92678cb44db264b0d3d4fe903263de922e
Author: Rajan Dhabalia <rd...@apache.org>
AuthorDate: Tue May 7 16:20:15 2019 -0700

    [pulsar-function] fix broken backward compatibility with v1-namespace while registering function (#4224)
---
 .../pulsar/functions/worker/rest/api/ComponentImpl.java      | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java
index d844972..bb9a991 100644
--- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java
+++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java
@@ -316,10 +316,14 @@ public abstract class ComponentImpl {
             final TenantInfo tenantInfo = worker().getBrokerAdmin().tenants().getTenantInfo(tenant);
 
             String qualifiedNamespace = tenant + "/" + namespace;
-            if (!worker().getBrokerAdmin().namespaces().getNamespaces(tenant).contains(qualifiedNamespace)) {
-                log.error("{}/{}/{} Namespace {} does not exist", tenant, namespace,
-                        componentName, namespace);
-                throw new RestException(Status.BAD_REQUEST, "Namespace does not exist");
+            List<String> namespaces = worker().getBrokerAdmin().namespaces().getNamespaces(tenant);
+            if (namespaces != null && !namespaces.contains(qualifiedNamespace)) {
+                String qualifiedNamespaceWithCluster = String.format("%s/%s/%s", tenant,
+                        worker().getWorkerConfig().getPulsarFunctionsCluster(), namespace);
+                if (namespaces != null && !namespaces.contains(qualifiedNamespaceWithCluster)) {
+                    log.error("{}/{}/{} Namespace {} does not exist", tenant, namespace, componentName, namespace);
+                    throw new RestException(Status.BAD_REQUEST, "Namespace does not exist");
+                }
             }
         } catch (PulsarAdminException.NotAuthorizedException e) {
             log.error("{}/{}/{} Client [{}] is not admin and authorized to operate {} on tenant", tenant, namespace,