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