merlimat closed pull request #1504: Enable FQFN specification for the Pulsar 
Functions CLI
URL: https://github.com/apache/incubator-pulsar/pull/1504
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git 
a/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/CmdFunctionsTest.java
 
b/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/CmdFunctionsTest.java
index 7bcb1090c5..5f745d15a8 100644
--- 
a/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/CmdFunctionsTest.java
+++ 
b/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/CmdFunctionsTest.java
@@ -232,6 +232,31 @@ public void testCreateWithoutNamespace() throws Exception {
         verify(functions, times(1)).createFunction(any(FunctionConfig.class), 
anyString());
     }
 
+    @Test
+    public void testCreateUsingFullyQualifiedFunctionName() throws Exception {
+        String inputTopicName = TEST_NAME + "-input-topic";
+        String outputTopicName = TEST_NAME + "-output-topic";
+        String tenant = "sample";
+        String namespace = "ns1";
+        String functionName = "func";
+        String fqfn = String.format("%s/%s/%s", tenant, namespace, 
functionName);
+
+        cmd.run(new String[] {
+                "create",
+                "--inputs", inputTopicName,
+                "--output", outputTopicName,
+                "--fqfn", fqfn,
+                "--jar", "SomeJar.jar",
+                "--className", DummyFunction.class.getName(),
+        });
+
+        CreateFunction creater = cmd.getCreater();
+        assertEquals(tenant, creater.getFunctionConfig().getTenant());
+        assertEquals(namespace, creater.getFunctionConfig().getNamespace());
+        assertEquals(functionName, creater.getFunctionConfig().getName());
+        verify(functions, times(1)).createFunction(any(FunctionConfig.class), 
anyString());
+    }
+
     @Test
     public void testCreateWithoutFunctionName() throws Exception {
         String inputTopicName = TEST_NAME + "-input-topic";
diff --git 
a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdFunctions.java
 
b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdFunctions.java
index e3951abdcb..adf7283b13 100644
--- 
a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdFunctions.java
+++ 
b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdFunctions.java
@@ -103,6 +103,9 @@ void processArguments() throws Exception {}
      */
     @Getter
     abstract class NamespaceCommand extends BaseCommand {
+        @Parameter(names = "--fqfn", description = "The Fully Qualified 
Function Name (FQFN) for the function", required = false)
+        protected String fqfn;
+
         @Parameter(names = "--tenant", description = "The function's tenant", 
required = true)
         protected String tenant;
 
@@ -124,6 +127,8 @@ void processArguments() throws Exception {}
      */
     @Getter
     abstract class FunctionConfigCommand extends BaseCommand {
+        @Parameter(names = "--fqfn", description = "The Fully Qualified 
Function Name (FQFN) for the function")
+        protected String fqfn;
         @Parameter(names = "--tenant", description = "The function's tenant")
         protected String tenant;
         @Parameter(names = "--namespace", description = "The function's 
namespace")
@@ -168,13 +173,29 @@ void processArguments() throws Exception {}
 
         @Override
         void processArguments() throws Exception {
-
             FunctionConfig.Builder functionConfigBuilder;
+
+            // Initialize config builder either from a supplied YAML config 
file or from scratch
             if (null != fnConfigFile) {
                 functionConfigBuilder = loadConfig(new File(fnConfigFile));
             } else {
                 functionConfigBuilder = FunctionConfig.newBuilder();
             }
+
+            if (null != fqfn) {
+                parseFullyQualifiedFunctionName(fqfn, functionConfigBuilder);
+            } else {
+                if (null != tenant) {
+                    functionConfigBuilder.setTenant(tenant);
+                }
+                if (null != namespace) {
+                    functionConfigBuilder.setNamespace(namespace);
+                }
+                if (null != functionName) {
+                    functionConfigBuilder.setName(functionName);
+                }
+            }
+
             if (null != inputs) {
                 String[] topicNames = inputs.split(",");
                 for (int i = 0; i < topicNames.length; ++i) {
@@ -192,15 +213,6 @@ void processArguments() throws Exception {
             if (null != logTopic) {
                 functionConfigBuilder.setLogTopic(logTopic);
             }
-            if (null != tenant) {
-                functionConfigBuilder.setTenant(tenant);
-            }
-            if (null != namespace) {
-                functionConfigBuilder.setNamespace(namespace);
-            }
-            if (null != functionName) {
-                functionConfigBuilder.setName(functionName);
-            }
             if (null != className) {
                 functionConfigBuilder.setClassName(className);
             }
@@ -373,6 +385,17 @@ private void doJavaSubmitChecks(FunctionConfig.Builder 
functionConfigBuilder) {
             }
         }
 
+        private void parseFullyQualifiedFunctionName(String fqfn, 
FunctionConfig.Builder functionConfigBuilder) {
+            String[] args = fqfn.split("/");
+            if (args.length != 3) {
+                throw new RuntimeException("Fully qualified function names 
must be of the form tenant/namespace/name");
+            } else {
+                functionConfigBuilder.setTenant(args[0]);
+                functionConfigBuilder.setNamespace(args[1]);
+                functionConfigBuilder.setName(args[2]);
+            }
+        }
+
         private void doPythonSubmitChecks(FunctionConfig.Builder 
functionConfigBuilder) {
             if (functionConfigBuilder.getProcessingGuarantees() == 
FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE) {
                 throw new RuntimeException("Effectively-once processing 
guarantees not yet supported in Python");
@@ -702,7 +725,7 @@ StateGetter getStateGetter() {
     TriggerFunction getTriggerer() {
         return triggerer;
     }
-    
+
     private static FunctionConfig.Builder loadConfig(File file) throws 
IOException {
         String json = FunctionConfigUtils.convertYamlToJson(file);
         FunctionConfig.Builder functionConfigBuilder = 
FunctionConfig.newBuilder();
diff --git a/pulsar-functions/proto/src/main/proto/Function.proto 
b/pulsar-functions/proto/src/main/proto/Function.proto
index 4b74dc73e5..542d847c4d 100644
--- a/pulsar-functions/proto/src/main/proto/Function.proto
+++ b/pulsar-functions/proto/src/main/proto/Function.proto
@@ -53,6 +53,9 @@ message FunctionConfig {
     bool autoAck = 13;
     repeated string inputs = 14;
     int32 parallelism = 15;
+    // Fully qualified function name
+    // (alternative to specifying tenant/namespace/name)
+    string fqfn = 16;
 }
 
 message PackageLocationMetaData {
diff --git a/site/_includes/fqfn.html b/site/_includes/fqfn.html
new file mode 100644
index 0000000000..4ab61b6901
--- /dev/null
+++ b/site/_includes/fqfn.html
@@ -0,0 +1,23 @@
+<!--
+
+    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.
+
+-->
+<section class="fqfn">
+  <span class="tenant">{{ include.tenant }}</span>/<span class="namespace">{{ 
include.namespace }}</span>/<span class="name">{{ include.name }}</span>
+</section>
\ No newline at end of file
diff --git a/site/_sass/_docs.scss b/site/_sass/_docs.scss
index 42277f070c..fcf2ca7791 100644
--- a/site/_sass/_docs.scss
+++ b/site/_sass/_docs.scss
@@ -109,7 +109,7 @@
         }
       }
 
-      .topic {
+      .topic, .fqfn {
         color: $sx-light-gray;
         background-color: $black;
         font-size: $code-font-size;
@@ -117,8 +117,8 @@
         padding: 10px 0 10px 20px;
         border-radius: 0;
 
-        .property { color: $sx-olive; }
-        .cluster { color: $sx-red; }
+        .property, .tenant { color: $sx-olive; }
+        .cluster, .name { color: $sx-red; }
         .namespace { color: $sx-7; }
         .t { color: $sx-magenta; }
 
diff --git a/site/docs/latest/functions/overview.md 
b/site/docs/latest/functions/overview.md
index 764515d912..d72bf4423b 100644
--- a/site/docs/latest/functions/overview.md
+++ b/site/docs/latest/functions/overview.md
@@ -55,6 +55,14 @@ $ bin/pulsar-functions localrun \
   --className org.apache.pulsar.functions.api.examples.ExclamationFunction
 ```
 
+## Fully Qualified Function Name (FQFN) {#fqfn}
+
+Each Pulsar Function has a **Fully Qualified Function Name** (FQFN) that 
consists of three elements: the function's {% popover tenant %}, {% popover 
namespace %}, and function name. FQFN's look like this:
+
+{% include fqfn.html tenant="tenant" namespace="namespace" name="name" %}
+
+FQFNs enable you to, for example, create multiple functions with the same name 
provided that they're in different namespaces.
+
 ## Configuration
 
 Pulsar Functions can be configured in two ways:


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to