You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/03/23 06:32:32 UTC
(camel) branch main updated: CAMEL-20606: Add Camel K bind command (#13595)
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new eb36ce03bf1 CAMEL-20606: Add Camel K bind command (#13595)
eb36ce03bf1 is described below
commit eb36ce03bf1d19b447133216d8d64eb33e16734e
Author: Christoph Deppisch <cd...@redhat.com>
AuthorDate: Sat Mar 23 07:32:26 2024 +0100
CAMEL-20606: Add Camel K bind command (#13595)
- Enhance Camel JBang bind command with Kubernetes and Camel K specifics such as traits, annotations, service bindings
- Uses arbitrary bind command as a base
- Makes sure to use a proper Camel K operator id
---
.../apache/camel/dsl/jbang/core/commands/Bind.java | 90 +++++++--
.../camel/dsl/jbang/core/commands/k/Bind.java | 184 ++++++++++++++++++
.../dsl/jbang/core/commands/k/IntegrationRun.java | 17 +-
.../dsl/jbang/core/commands/k/KubePlugin.java | 1 +
.../templates/pipe-kamelet-kamelet.yaml.tmpl | 21 ++
.../resources/templates/pipe-kamelet-uri.yaml.tmpl | 18 ++
.../resources/templates/pipe-uri-kamelet.yaml.tmpl | 18 ++
.../resources/templates/pipe-uri-uri.yaml.tmpl | 15 ++
.../camel/dsl/jbang/core/commands/k/BindTest.java | 215 +++++++++++++++++++++
.../jbang/core/commands/k/IntegrationRunTest.java | 14 ++
10 files changed, 576 insertions(+), 17 deletions(-)
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java
index c5bc9e3809c..3a005645342 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java
@@ -84,12 +84,50 @@ public class Bind extends CamelCommand {
description = "Output format generated by this command (supports: file, yaml or json).")
String output;
+ private final TemplateProvider templateProvider;
+
public Bind(CamelJBangMain main) {
+ this(main, new TemplateProvider() {
+ });
+ }
+
+ public Bind(CamelJBangMain main, TemplateProvider templateProvider) {
super(main);
+ this.templateProvider = templateProvider;
+ }
+
+ /**
+ * Helper class provides access to the templates that construct the Pipe resource. Subclasses may overwrite the
+ * provider to inject their own templates.
+ */
+ public interface TemplateProvider {
+ default InputStream getPipeTemplate(String in, String out) {
+ return Bind.class.getClassLoader().getResourceAsStream("templates/pipe-" + in + "-" + out + ".yaml.tmpl");
+ }
+
+ default InputStream getStepTemplate(String stepType) {
+ return Bind.class.getClassLoader().getResourceAsStream("templates/step-%s.yaml.tmpl".formatted(stepType));
+ }
+
+ default InputStream getErrorHandlerTemplate(String type) {
+ return Bind.class.getClassLoader()
+ .getResourceAsStream("templates/error-handler-%s.yaml.tmpl".formatted(type));
+ }
}
@Override
public Integer doCall() throws Exception {
+ String pipe = constructPipe();
+
+ if (pipe.isEmpty()) {
+ printer().println("Failed to construct Pipe resource");
+ return -1;
+ }
+
+ return dumpPipe(pipe);
+ }
+
+ public String constructPipe() throws Exception {
// the pipe source and sink can either be a kamelet or an uri
String in = "kamelet";
String out = "kamelet";
@@ -119,7 +157,7 @@ public class Bind extends CamelCommand {
}
}
- InputStream is = Bind.class.getClassLoader().getResourceAsStream("templates/pipe-" + in + "-" + out + ".yaml.tmpl");
+ InputStream is = templateProvider.getPipeTemplate(in, out);
String context = IOHelper.loadText(is);
IOHelper.close(is);
@@ -146,7 +184,7 @@ public class Bind extends CamelCommand {
stepProperties = kameletProperties(step, stepProperties);
}
- is = Bind.class.getClassLoader().getResourceAsStream("templates/step-%s.yaml.tmpl".formatted(stepType));
+ is = templateProvider.getStepTemplate(stepType);
text = IOHelper.loadText(is);
IOHelper.close(is);
text = text.replaceFirst("\\{\\{ \\.Name }}", step);
@@ -176,7 +214,8 @@ public class Bind extends CamelCommand {
if (errorHandlerTokens.length != 2) {
printer().println(
"Invalid error handler syntax. Type 'sink' needs an endpoint configuration (ie sink:endpointUri)");
- return -1;
+ // Error abort Pipe construction
+ return "";
}
String endpoint = errorHandlerTokens[1];
@@ -203,8 +242,7 @@ public class Bind extends CamelCommand {
errorHandlerSinkProperties = kameletProperties(endpoint, errorHandlerSinkProperties);
}
- is = Bind.class.getClassLoader()
- .getResourceAsStream("templates/error-handler-sink-%s.yaml.tmpl".formatted(sinkType));
+ is = templateProvider.getErrorHandlerTemplate("sink-" + sinkType);
errorHandlerSpec = IOHelper.loadText(is);
IOHelper.close(is);
errorHandlerSpec = errorHandlerSpec.replaceFirst("\\{\\{ \\.Name }}", endpoint);
@@ -214,7 +252,7 @@ public class Bind extends CamelCommand {
asErrorHandlerParameters(errorHandlerParameters));
break;
case "log":
- is = Bind.class.getClassLoader().getResourceAsStream("templates/error-handler-log.yaml.tmpl");
+ is = templateProvider.getErrorHandlerTemplate("log");
errorHandlerSpec = IOHelper.loadText(is);
IOHelper.close(is);
errorHandlerSpec = errorHandlerSpec.replaceFirst("\\{\\{ \\.ErrorHandlerParameter }}",
@@ -249,23 +287,26 @@ public class Bind extends CamelCommand {
sinkProperties.putAll(sinkUriProperties);
}
context = context.replaceFirst("\\{\\{ \\.SinkProperties }}\n", asEndpointProperties(sinkProperties));
+ return context;
+ }
+ public int dumpPipe(String pipe) throws Exception {
switch (output) {
case "file":
if (file.endsWith(".yaml")) {
- IOHelper.writeText(context, new FileOutputStream(file, false));
+ IOHelper.writeText(pipe, new FileOutputStream(file, false));
} else if (file.endsWith(".json")) {
- IOHelper.writeText(Jsoner.serialize(YamlHelper.yaml().loadAs(context, Map.class)),
+ IOHelper.writeText(Jsoner.serialize(YamlHelper.yaml().loadAs(pipe, Map.class)),
new FileOutputStream(file, false));
} else {
- IOHelper.writeText(context, new FileOutputStream(file + ".yaml", false));
+ IOHelper.writeText(pipe, new FileOutputStream(file + ".yaml", false));
}
break;
case "yaml":
- printer().println(context);
+ printer().println(pipe);
break;
case "json":
- printer().println(JSonHelper.prettyPrint(Jsoner.serialize(YamlHelper.yaml().loadAs(context, Map.class)), 2)
+ printer().println(JSonHelper.prettyPrint(Jsoner.serialize(YamlHelper.yaml().loadAs(pipe, Map.class)), 2)
.replaceAll("\\\\/", "/"));
break;
default:
@@ -442,4 +483,31 @@ public class Bind extends CamelCommand {
}
}
+ public void setFile(String file) {
+ this.file = file;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public void setSink(String sink) {
+ this.sink = sink;
+ }
+
+ public void setSteps(String[] steps) {
+ this.steps = steps;
+ }
+
+ public void setProperties(String[] properties) {
+ this.properties = properties;
+ }
+
+ public void setErrorHandler(String errorHandler) {
+ this.errorHandler = errorHandler;
+ }
+
+ public void setOutput(String output) {
+ this.output = output;
+ }
}
diff --git a/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/Bind.java b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/Bind.java
new file mode 100644
index 00000000000..c536045c68f
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/Bind.java
@@ -0,0 +1,184 @@
+/*
+ * 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.camel.dsl.jbang.core.commands.k;
+
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Stack;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.v1.integrationspec.Traits;
+import org.apache.camel.v1.integrationspec.traits.ServiceBinding;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+@Command(name = "bind",
+ description = "Bind Kubernetes resources such as Kamelets in a new integration pipe connecting a source and a sink",
+ sortOptions = false)
+public class Bind extends KubeBaseCommand {
+
+ private final org.apache.camel.dsl.jbang.core.commands.Bind delegate;
+
+ @CommandLine.Parameters(description = "Name of pipe", arity = "1",
+ paramLabel = "<name>", parameterConsumer = NameConsumer.class)
+ Path pipeName; // Defined only for code completion; the field never used
+ String name;
+
+ @CommandLine.Option(names = { "--source" }, description = "Source (from) such as a Kamelet or Camel endpoint uri",
+ required = true)
+ String source;
+
+ @CommandLine.Option(names = { "--step" }, description = "Optional steps such as a Kamelet or Camel endpoint uri")
+ String[] steps;
+
+ @CommandLine.Option(names = { "--sink" }, description = "Sink (to) such as a Kamelet or Camel endpoint uri",
+ required = true)
+ String sink;
+
+ @CommandLine.Option(names = { "--error-handler" },
+ description = "Add error handler (none|log|sink:<endpoint>). Sink endpoints are expected in the format \"[[apigroup/]version:]kind:[namespace/]name\", plain Camel URIs or Kamelet name.")
+ String errorHandler;
+
+ @CommandLine.Option(names = { "--property" },
+ description = "Adds a pipe property in the form of [source|sink|step-<n>].<key>=<value> where <n> is the step number starting from 1",
+ arity = "0")
+ String[] properties;
+
+ @CommandLine.Option(names = { "--output" },
+ defaultValue = "file",
+ description = "Output format generated by this command (supports: file, yaml or json).")
+ String output;
+
+ @CommandLine.Option(names = { "--operator-id" },
+ defaultValue = "camel-k",
+ description = "Operator id selected to manage this integration.")
+ String operatorId = "camel-k";
+
+ @CommandLine.Option(names = { "--connect" },
+ description = "A Service that the integration should bind to, specified as [[apigroup/]version:]kind:[namespace/]name.")
+ String[] connects;
+
+ @CommandLine.Option(names = { "--annotation" },
+ description = "Add an annotation to the integration. Use name values pairs like \"--annotation my.company=hello\".")
+ String[] annotations;
+
+ @CommandLine.Option(names = { "--traits" },
+ description = "Add a label to the integration. Use name values pairs like \"--label my.company=hello\".")
+ String[] traits;
+
+ public Bind(CamelJBangMain main) {
+ super(main);
+ delegate = new org.apache.camel.dsl.jbang.core.commands.Bind(
+ main, new org.apache.camel.dsl.jbang.core.commands.Bind.TemplateProvider() {
+ @Override
+ public InputStream getPipeTemplate(String in, String out) {
+ return Bind.class.getClassLoader()
+ .getResourceAsStream("templates/pipe-" + in + "-" + out + ".yaml.tmpl");
+ }
+ });
+ }
+
+ @Override
+ public Integer doCall() throws Exception {
+ // Operator id must be set
+ if (ObjectHelper.isEmpty(operatorId)) {
+ printer().println("Operator id must be set");
+ return -1;
+ }
+
+ delegate.setFile(name);
+ delegate.setSource(source);
+ delegate.setSink(sink);
+ delegate.setSteps(steps);
+ delegate.setErrorHandler(errorHandler);
+ delegate.setProperties(properties);
+ delegate.setOutput(output);
+
+ String pipe = delegate.constructPipe();
+
+ if (pipe.isEmpty()) {
+ // Error in delegate exit now
+ printer().println("Failed to construct Pipe resource");
+ return -1;
+ }
+
+ // --operator-id={id} is a syntax sugar for '--annotation camel.apache.org/operator.id={id}'
+ if (annotations == null) {
+ annotations = new String[] { "%s=%s".formatted(KubeCommand.OPERATOR_ID_LABEL, operatorId) };
+ } else {
+ annotations = Arrays.copyOf(annotations, annotations.length + 1);
+ annotations[annotations.length - 1] = "%s=%s".formatted(KubeCommand.OPERATOR_ID_LABEL, operatorId);
+ }
+
+ String annotationsContext = "";
+ if (annotations != null) {
+ StringBuilder sb = new StringBuilder(" annotations:\n");
+
+ for (String annotation : annotations) {
+ String[] keyValue = annotation.split("=", 2);
+ if (keyValue.length != 2) {
+ printer().printf(
+ "annotation '%s' does not follow format <key>=<value>%n",
+ annotation);
+ continue;
+ }
+
+ sb.append(" ").append(keyValue[0]).append(": ").append(keyValue[1]).append("\n");
+ }
+
+ annotationsContext = sb.toString();
+ }
+
+ pipe = pipe.replaceFirst("\\{\\{ \\.Annotations }}\n", annotationsContext);
+
+ String integrationSpec = "";
+ Traits traitsSpec = null;
+ if (traits != null && traits.length > 0) {
+ traitsSpec = TraitHelper.parseTraits(traits);
+ }
+
+ if (connects != null && connects.length > 0) {
+ if (traitsSpec == null) {
+ traitsSpec = new Traits();
+ }
+
+ ServiceBinding serviceBindingTrait = new ServiceBinding();
+ serviceBindingTrait.setServices(List.of(connects));
+ traitsSpec.setServiceBinding(serviceBindingTrait);
+ }
+
+ if (traitsSpec != null) {
+ String traitYaml = KubernetesHelper.yaml().dumpAsMap(traitsSpec).replaceAll("\n", "\n ");
+ integrationSpec = " integration:\n spec:\n traits:\n %s\n".formatted(traitYaml.trim());
+ }
+
+ pipe = pipe.replaceFirst("\\{\\{ \\.IntegrationSpec }}\n", integrationSpec);
+
+ return delegate.dumpPipe(pipe);
+ }
+
+ static class NameConsumer extends ParameterConsumer<Bind> {
+ @Override
+ protected void doConsumeParameters(Stack<String> args, Bind cmd) {
+ cmd.name = args.pop();
+ }
+ }
+
+}
diff --git a/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/IntegrationRun.java b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/IntegrationRun.java
index 6d5b5a267ca..a435ad67b14 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/IntegrationRun.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/IntegrationRun.java
@@ -173,6 +173,12 @@ public class IntegrationRun extends KubeBaseCommand {
}
public Integer doCall() throws Exception {
+ // Operator id must be set
+ if (ObjectHelper.isEmpty(operatorId)) {
+ printer().println("Operator id must be set");
+ return -1;
+ }
+
List<String> integrationSources
= Stream.concat(Arrays.stream(Optional.ofNullable(filePaths).orElseGet(() -> new String[] {})),
Arrays.stream(Optional.ofNullable(sources).orElseGet(() -> new String[] {}))).toList();
@@ -216,14 +222,13 @@ public class IntegrationRun extends KubeBaseCommand {
.collect(Collectors.toMap(it -> it[0].trim(), it -> it[1].trim())));
}
- if (operatorId != null) {
- if (integration.getMetadata().getAnnotations() == null) {
- integration.getMetadata().setAnnotations(new HashMap<>());
- }
-
- integration.getMetadata().getAnnotations().put(KubeCommand.OPERATOR_ID_LABEL, operatorId);
+ if (integration.getMetadata().getAnnotations() == null) {
+ integration.getMetadata().setAnnotations(new HashMap<>());
}
+ // --operator-id={id} is a syntax sugar for '--annotation camel.apache.org/operator.id={id}'
+ integration.getMetadata().getAnnotations().put(KubeCommand.OPERATOR_ID_LABEL, operatorId);
+
if (labels != null && labels.length > 0) {
integration.getMetadata().setLabels(Arrays.stream(labels)
.filter(it -> it.contains("="))
diff --git a/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/KubePlugin.java b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/KubePlugin.java
index 6da3e3fa6da..7d10cac8e09 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/KubePlugin.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/java/org/apache/camel/dsl/jbang/core/commands/k/KubePlugin.java
@@ -31,6 +31,7 @@ public class KubePlugin implements Plugin {
.addSubcommand(Agent.ID, new picocli.CommandLine(new Agent(main)))
.addSubcommand("get", new picocli.CommandLine(new IntegrationGet(main)))
.addSubcommand("run", new picocli.CommandLine(new IntegrationRun(main)))
+ .addSubcommand("bind", new picocli.CommandLine(new Bind(main)))
.addSubcommand("delete", new picocli.CommandLine(new IntegrationDelete(main)))
.addSubcommand("logs", new picocli.CommandLine(new IntegrationLogs(main)));
diff --git a/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-kamelet-kamelet.yaml.tmpl b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-kamelet-kamelet.yaml.tmpl
new file mode 100644
index 00000000000..400ae37bedf
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-kamelet-kamelet.yaml.tmpl
@@ -0,0 +1,21 @@
+apiVersion: camel.apache.org/v1
+kind: Pipe
+metadata:
+ name: {{ .Name }}
+{{ .Annotations }}
+spec:
+{{ .IntegrationSpec }}
+ source:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: {{ .Source }}
+ {{ .SourceProperties }}
+{{ .Steps }}
+ sink:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: {{ .Sink }}
+ {{ .SinkProperties }}
+{{ .ErrorHandler }}
diff --git a/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-kamelet-uri.yaml.tmpl b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-kamelet-uri.yaml.tmpl
new file mode 100644
index 00000000000..1ac52571ece
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-kamelet-uri.yaml.tmpl
@@ -0,0 +1,18 @@
+apiVersion: camel.apache.org/v1
+kind: Pipe
+metadata:
+ name: {{ .Name }}
+{{ .Annotations }}
+spec:
+{{ .IntegrationSpec }}
+ source:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: {{ .Source }}
+ {{ .SourceProperties }}
+{{ .Steps }}
+ sink:
+ uri: {{ .Sink }}
+ {{ .SinkProperties }}
+{{ .ErrorHandler }}
diff --git a/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-uri-kamelet.yaml.tmpl b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-uri-kamelet.yaml.tmpl
new file mode 100644
index 00000000000..e6c33789d94
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-uri-kamelet.yaml.tmpl
@@ -0,0 +1,18 @@
+apiVersion: camel.apache.org/v1
+kind: Pipe
+metadata:
+ name: {{ .Name }}
+{{ .Annotations }}
+spec:
+{{ .IntegrationSpec }}
+ source:
+ uri: {{ .Source }}
+ {{ .SourceProperties }}
+{{ .Steps }}
+ sink:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: {{ .Sink }}
+ {{ .SinkProperties }}
+{{ .ErrorHandler }}
diff --git a/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-uri-uri.yaml.tmpl b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-uri-uri.yaml.tmpl
new file mode 100644
index 00000000000..2a181b6ece5
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-plugin-k/src/main/resources/templates/pipe-uri-uri.yaml.tmpl
@@ -0,0 +1,15 @@
+apiVersion: camel.apache.org/v1
+kind: Pipe
+metadata:
+ name: {{ .Name }}
+{{ .Annotations }}
+spec:
+{{ .IntegrationSpec }}
+ source:
+ uri: {{ .Source }}
+ {{ .SourceProperties }}
+{{ .Steps }}
+ sink:
+ uri: {{ .Sink }}
+ {{ .SinkProperties }}
+{{ .ErrorHandler }}
diff --git a/dsl/camel-jbang/camel-jbang-plugin-k/src/test/java/org/apache/camel/dsl/jbang/core/commands/k/BindTest.java b/dsl/camel-jbang/camel-jbang-plugin-k/src/test/java/org/apache/camel/dsl/jbang/core/commands/k/BindTest.java
new file mode 100644
index 00000000000..9809bf44ee7
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-plugin-k/src/test/java/org/apache/camel/dsl/jbang/core/commands/k/BindTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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.camel.dsl.jbang.core.commands.k;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class BindTest extends KubeBaseTest {
+
+ @Test
+ public void shouldBindWithDefaultOperatorId() throws Exception {
+ Bind command = new Bind(new CamelJBangMain().withPrinter(printer));
+ command.name = "timer-to-log";
+ command.source = "timer-source";
+ command.sink = "log-sink";
+ command.output = "yaml";
+
+ command.doCall();
+
+ String output = printer.getOutput();
+ Assertions.assertEquals("""
+ apiVersion: camel.apache.org/v1
+ kind: Pipe
+ metadata:
+ name: timer-to-log
+ annotations:
+ camel.apache.org/operator.id: camel-k
+ spec:
+ source:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: timer-source
+ properties:
+ message: "hello world"
+ sink:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: log-sink
+ #properties:
+ #key: "value"
+ """.trim(), output);
+ }
+
+ @Test
+ public void shouldBindWithAnnotations() throws Exception {
+ Bind command = new Bind(new CamelJBangMain().withPrinter(printer));
+ command.name = "timer-to-log";
+ command.source = "timer-source";
+ command.sink = "log-sink";
+ command.output = "yaml";
+
+ command.annotations = new String[] {
+ "app=camel-k"
+ };
+
+ command.doCall();
+
+ String output = printer.getOutput();
+ Assertions.assertEquals("""
+ apiVersion: camel.apache.org/v1
+ kind: Pipe
+ metadata:
+ name: timer-to-log
+ annotations:
+ app: camel-k
+ camel.apache.org/operator.id: camel-k
+ spec:
+ source:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: timer-source
+ properties:
+ message: "hello world"
+ sink:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: log-sink
+ #properties:
+ #key: "value"
+ """.trim(), output);
+ }
+
+ @Test
+ public void shouldBindWithTraits() throws Exception {
+ Bind command = new Bind(new CamelJBangMain().withPrinter(printer));
+ command.name = "timer-to-log";
+ command.source = "timer-source";
+ command.sink = "log-sink";
+ command.output = "yaml";
+
+ command.traits = new String[] {
+ "mount.configs=configmap:my-cm",
+ "logging.color=true",
+ "logging.level=DEBUG"
+ };
+
+ command.doCall();
+
+ String output = printer.getOutput();
+ Assertions.assertEquals("""
+ apiVersion: camel.apache.org/v1
+ kind: Pipe
+ metadata:
+ name: timer-to-log
+ annotations:
+ camel.apache.org/operator.id: camel-k
+ spec:
+ integration:
+ spec:
+ traits:
+ logging:
+ color: true
+ level: DEBUG
+ mount:
+ configs:
+ - configmap:my-cm
+ hotReload: false
+ source:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: timer-source
+ properties:
+ message: "hello world"
+ sink:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: log-sink
+ #properties:
+ #key: "value"
+ """.trim(), output);
+ }
+
+ @Test
+ public void shouldBindWithServiceBindings() throws Exception {
+ Bind command = new Bind(new CamelJBangMain().withPrinter(printer));
+ command.name = "timer-to-log";
+ command.source = "timer-source";
+ command.sink = "log-sink";
+ command.output = "yaml";
+
+ command.connects = new String[] {
+ "serving.knative.dev/v1:Service:my-service"
+ };
+
+ command.doCall();
+
+ String output = printer.getOutput();
+ Assertions.assertEquals("""
+ apiVersion: camel.apache.org/v1
+ kind: Pipe
+ metadata:
+ name: timer-to-log
+ annotations:
+ camel.apache.org/operator.id: camel-k
+ spec:
+ integration:
+ spec:
+ traits:
+ serviceBinding:
+ services:
+ - serving.knative.dev/v1:Service:my-service
+ source:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: timer-source
+ properties:
+ message: "hello world"
+ sink:
+ ref:
+ kind: Kamelet
+ apiVersion: camel.apache.org/v1
+ name: log-sink
+ #properties:
+ #key: "value"
+ """.trim(), output);
+ }
+
+ @Test
+ public void shouldFailWithMissingOperatorId() throws Exception {
+ Bind command = new Bind(new CamelJBangMain().withPrinter(printer));
+ command.name = "timer-to-log";
+ command.source = "timer-source";
+ command.sink = "log-sink";
+ command.output = "yaml";
+
+ command.operatorId = "";
+
+ Assertions.assertEquals(-1, command.doCall());
+
+ Assertions.assertEquals("Operator id must be set", printer.getOutput());
+ }
+}
diff --git a/dsl/camel-jbang/camel-jbang-plugin-k/src/test/java/org/apache/camel/dsl/jbang/core/commands/k/IntegrationRunTest.java b/dsl/camel-jbang/camel-jbang-plugin-k/src/test/java/org/apache/camel/dsl/jbang/core/commands/k/IntegrationRunTest.java
index 4dba66a0487..0a6a0e3df7c 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-k/src/test/java/org/apache/camel/dsl/jbang/core/commands/k/IntegrationRunTest.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-k/src/test/java/org/apache/camel/dsl/jbang/core/commands/k/IntegrationRunTest.java
@@ -642,6 +642,20 @@ class IntegrationRunTest extends KubeBaseTest {
traits: {}""", removeLicenseHeader(printer.getOutput()));
}
+ @Test
+ public void shouldFailWithMissingOperatorId() throws Exception {
+ IntegrationRun command = createCommand();
+ command.filePaths = new String[] { "classpath:route.yaml" };
+ command.useFlows = false;
+ command.output = "yaml";
+
+ command.operatorId = "";
+
+ Assertions.assertEquals(-1, command.doCall());
+
+ Assertions.assertEquals("Operator id must be set", printer.getOutput());
+ }
+
private IntegrationRun createCommand() {
IntegrationRun command = new IntegrationRun(new CamelJBangMain().withPrinter(printer));
command.withClient(kubernetesClient);