[api][pulsar-client]Add get version command for pulsar rest api, pulsar-admin, pulsar-client (#9975)

### Motivation

Add the version command:
Get broker version by rest API:

```
curl http://localhost:8080/admin/v2/brokers/version
```
Get broker version by `pulsar-admin`:
```
./bin/pulsar-admin brokers version
```
Get broker version by the command `pulsar`:
```
./bin/pulsar version
```

Get version of pulsar admin client:
```
./bin/pulsar-admin -v
./bin/pulsra-admin --version
```

Get version of pulsar client:
```
./bin/pulsar-client -v
./bin/pulsra-client --version
diff --git a/bin/pulsar b/bin/pulsar
index ed6e9b2..d3908b2 100755
--- a/bin/pulsar
+++ b/bin/pulsar
@@ -150,6 +150,7 @@
     zookeeper-shell     Open a ZK shell client
     broker-tool         CLI to operate a specific broker
     tokens              Utility to create authentication tokens
+    version             Get the current version of pulsar
 
     help                This help message
 
@@ -365,7 +366,9 @@
     check_presto_libraries
     exec ${PRESTO_HOME}/bin/launcher --etc-dir ${PULSAR_PRESTO_CONF} "${@}"
 elif [ $COMMAND == "tokens" ]; then
-      exec $JAVA $OPTS org.apache.pulsar.utils.auth.tokens.TokensCliUtils $@
+    exec $JAVA $OPTS org.apache.pulsar.utils.auth.tokens.TokensCliUtils $@
+elif [ $COMMAND == "version" ]; then
+    exec $JAVA $OPTS org.apache.pulsar.PulsarVersionStarter $@
 elif [ $COMMAND == "help" -o $COMMAND == "--help" -o $COMMAND == "-h" ]; then
     pulsar_help;
 else
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarVersionStarter.java b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarVersionStarter.java
new file mode 100644
index 0000000..d3510f5
--- /dev/null
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarVersionStarter.java
@@ -0,0 +1,29 @@
+/**
+ * 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;
+
+/**
+ * Pulsar version entry point.
+ */
+public class PulsarVersionStarter {
+
+    public static void main(String args[]) {
+        System.out.println("Current version of pulsar is: " + PulsarVersion.getVersion());
+    }
+}
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java
index bb04c1b..5a41037 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java
@@ -41,6 +41,7 @@
 import javax.ws.rs.container.Suspended;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
+import org.apache.pulsar.PulsarVersion;
 import org.apache.pulsar.broker.PulsarService.State;
 import org.apache.pulsar.broker.ServiceConfiguration;
 import org.apache.pulsar.broker.loadbalance.LeaderBroker;
@@ -418,5 +419,15 @@
             throw new RestException(ie);
         }
     }
+
+    @GET
+    @Path("/version")
+    @ApiOperation(value = "Get version of current broker")
+    @ApiResponses(value = {
+            @ApiResponse(code = 200, message = "Everything is OK"),
+            @ApiResponse(code = 500, message = "Internal server error")})
+    public String version() throws Exception {
+        return PulsarVersion.getVersion();
+    }
 }
 
diff --git a/pulsar-client-admin-api/src/main/java/org/apache/pulsar/client/admin/Brokers.java b/pulsar-client-admin-api/src/main/java/org/apache/pulsar/client/admin/Brokers.java
index 11f7fd7..c444b2b 100644
--- a/pulsar-client-admin-api/src/main/java/org/apache/pulsar/client/admin/Brokers.java
+++ b/pulsar-client-admin-api/src/main/java/org/apache/pulsar/client/admin/Brokers.java
@@ -274,4 +274,10 @@
      * Run a healthcheck on the broker asynchronously.
      */
     CompletableFuture<Void> healthcheckAsync();
+
+    /**
+     * Get version of broker.
+     * @return version of broker.
+     */
+    String getVersion() throws PulsarAdminException;
 }
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/BrokersImpl.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/BrokersImpl.java
index 53b9e07..53a3703 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/BrokersImpl.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/BrokersImpl.java
@@ -388,4 +388,31 @@
                 });
         return future;
     }
+
+    @Override
+    public String getVersion() throws PulsarAdminException {
+        WebTarget path = adminBrokers.path("version");
+        try {
+            final CompletableFuture<String> future = new CompletableFuture<>();
+            asyncGetRequest(path, new InvocationCallback<String>() {
+                @Override
+                public void completed(String version) {
+                    future.complete(version);
+                }
+
+                @Override
+                public void failed(Throwable throwable) {
+                    future.completeExceptionally(getApiException(throwable.getCause()));
+                }
+            });
+            return future.get(this.readTimeoutMs, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException e) {
+            throw (PulsarAdminException) e.getCause();
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new PulsarAdminException(e);
+        } catch (TimeoutException e) {
+            throw new PulsarAdminException.TimeoutException(e);
+        }
+    }
 }
diff --git a/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/PulsarAdminToolTest.java b/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/PulsarAdminToolTest.java
index 005edc1..66bc53a 100644
--- a/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/PulsarAdminToolTest.java
+++ b/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/PulsarAdminToolTest.java
@@ -126,6 +126,9 @@
 
         brokers.run(split("healthcheck"));
         verify(mockBrokers).healthcheck();
+
+        brokers.run(split("version"));
+        verify(mockBrokers).getVersion();
     }
 
     @Test
diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdBrokers.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdBrokers.java
index 707629c..2aab374 100644
--- a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdBrokers.java
+++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdBrokers.java
@@ -146,6 +146,15 @@
 
     }
 
+    @Parameters(commandDescription = "Get the version of the currently connected broker")
+    private class PulsarVersion extends CliCommand {
+
+        @Override
+        void run() throws Exception {
+            System.out.println(getAdmin().brokers().getVersion());
+        }
+    }
+
     public CmdBrokers(Supplier<PulsarAdmin> admin) {
         super("brokers", admin);
         jcommander.addCommand("list", new List());
@@ -159,5 +168,6 @@
         jcommander.addCommand("get-runtime-config", new GetRuntimeConfigCmd());
         jcommander.addCommand("healthcheck", new HealthcheckCmd());
         jcommander.addCommand("backlog-quota-check", new BacklogQuotaCheckCmd());
+        jcommander.addCommand("version", new PulsarVersion());
     }
 }
diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/PulsarAdminTool.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/PulsarAdminTool.java
index 1659367..d50f199 100644
--- a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/PulsarAdminTool.java
+++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/PulsarAdminTool.java
@@ -31,8 +31,8 @@
 import java.util.function.Function;
 import java.util.function.Supplier;
 
-import lombok.AllArgsConstructor;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.pulsar.PulsarVersion;
 import org.apache.pulsar.client.admin.PulsarAdmin;
 import org.apache.pulsar.client.admin.PulsarAdminBuilder;
 import org.apache.pulsar.client.admin.internal.PulsarAdminImpl;
@@ -73,6 +73,9 @@
     @Parameter(names = { "--tls-enable-hostname-verification" }, description = "Enable TLS common name verification")
     Boolean tlsEnableHostnameVerification;
 
+    @Parameter(names = { "-v", "--version" }, description = "Get version of pulsar admin client")
+    boolean version;
+
     @Parameter(names = { "-h", "--help", }, help = true, description = "Show this help.")
     boolean help;
 
@@ -245,6 +248,11 @@
             return false;
         }
 
+        if (version) {
+            System.out.println("Current version of pulsar admin client is: " + PulsarVersion.getVersion());
+            return true;
+        }
+
         if (help) {
             setupCommands(adminFactory);
             jcommander.usage();
diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/client/cli/PulsarClientTool.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/client/cli/PulsarClientTool.java
index ab047dc..04fd44f 100644
--- a/pulsar-client-tools/src/main/java/org/apache/pulsar/client/cli/PulsarClientTool.java
+++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/client/cli/PulsarClientTool.java
@@ -26,6 +26,7 @@
 import java.util.Properties;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.pulsar.PulsarVersion;
 import org.apache.pulsar.client.api.Authentication;
 import org.apache.pulsar.client.api.AuthenticationFactory;
 import org.apache.pulsar.client.api.ClientBuilder;
@@ -65,6 +66,9 @@
             "or \"{\"key1\":\"val1\",\"key2\":\"val2\"}.")
     String authParams = null;
 
+    @Parameter(names = { "-v", "--version" }, description = "Get version of pulsar client")
+    boolean version;
+
     @Parameter(names = { "-h", "--help", }, help = true, description = "Show this help.")
     boolean help;
 
@@ -156,6 +160,11 @@
                 return -1;
             }
 
+            if (version) {
+                System.out.println("Current version of pulsar client is: " + PulsarVersion.getVersion());
+                return 0;
+            }
+
             if (help) {
                 commandParser.usage();
                 return 0;
diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/cli/PulsarVersionTest.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/cli/PulsarVersionTest.java
new file mode 100644
index 0000000..756d5d4
--- /dev/null
+++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/cli/PulsarVersionTest.java
@@ -0,0 +1,73 @@
+/**
+ * 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.tests.integration.cli;
+
+import org.apache.pulsar.tests.integration.docker.ContainerExecResult;
+import org.apache.pulsar.tests.integration.topologies.PulsarCluster;
+import org.apache.pulsar.tests.integration.topologies.PulsarClusterSpec;
+import org.testcontainers.shaded.org.apache.commons.lang.RandomStringUtils;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Pulsar version test class.
+ */
+public class PulsarVersionTest {
+
+    private final static String clusterNamePrefix = "pulsar-version";
+    private PulsarCluster pulsarCluster;
+
+    @BeforeClass
+    public void setup() throws Exception {
+        PulsarClusterSpec spec = PulsarClusterSpec.builder()
+                .clusterName(String.format("%s-%s", clusterNamePrefix, RandomStringUtils.randomAlphabetic(6)))
+                .build();
+        pulsarCluster = PulsarCluster.forSpec(spec);
+        pulsarCluster.start();
+    }
+
+    @AfterClass(alwaysRun = true)
+    public void teardown() {
+        if (pulsarCluster != null) {
+            pulsarCluster.stop();
+            pulsarCluster = null;
+        }
+    }
+
+    @Test
+    public void getVersion() throws Exception {
+        ContainerExecResult result = pulsarCluster.runAdminCommandOnAnyBroker("brokers", "version");
+        String version = result.getStdout();
+        ContainerExecResult adminVersionShortOption = pulsarCluster.runAdminCommandOnAnyBroker("-v");
+        assertTrue(adminVersionShortOption.getStdout().contains(version));
+        ContainerExecResult adminVersionLongOption = pulsarCluster.runAdminCommandOnAnyBroker("--version");
+        assertTrue(adminVersionLongOption.getStdout().contains(version));
+        ContainerExecResult clientVersionShortOption = pulsarCluster.getAnyBroker().execCmd(
+                PulsarCluster.CLIENT_SCRIPT, "-v");
+        assertTrue(clientVersionShortOption.getStdout().contains(version));
+        ContainerExecResult clientVersionLongOption = pulsarCluster.getAnyBroker().execCmd(
+                PulsarCluster.CLIENT_SCRIPT, "--version");
+        assertTrue(clientVersionLongOption.getStdout().contains(version));
+    }
+
+}
diff --git a/tests/integration/src/test/resources/pulsar-cli.xml b/tests/integration/src/test/resources/pulsar-cli.xml
index d6a9a15..847f492 100644
--- a/tests/integration/src/test/resources/pulsar-cli.xml
+++ b/tests/integration/src/test/resources/pulsar-cli.xml
@@ -29,6 +29,7 @@
             <class name="org.apache.pulsar.tests.integration.cli.AdminMultiHostTest"/>
             <class name="org.apache.pulsar.tests.integration.cli.FunctionsCLITest"/>
             <class name="org.apache.pulsar.tests.integration.cli.PackagesCliTest"/>
+            <class name="org.apache.pulsar.tests.integration.cli.PulsarVersionTest"/>
         </classes>
     </test>
 </suite>