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 22e73302fa7 CAMEL-21087: Add jolokia trait to Camel Jbang Kubernetes plugin (#18159) 22e73302fa7 is described below commit 22e73302fa7cb4cf99955eaaad3b09a6c99234ef Author: Gaƫlle Fournier <gaelle.fournier.w...@gmail.com> AuthorDate: Fri May 23 08:15:50 2025 +0200 CAMEL-21087: Add jolokia trait to Camel Jbang Kubernetes plugin (#18159) --- .../modules/ROOT/pages/camel-jbang-kubernetes.adoc | 104 +++++++++++++++++++ .../commands/kubernetes/traits/JolokiaTrait.java | 93 +++++++++++++++++ .../commands/kubernetes/traits/TraitCatalog.java | 1 + .../commands/kubernetes/traits/model/Jolokia.java | 110 +++++++++++++++++++++ .../kubernetes/traits/model/JolokiaBuilder.java | 74 ++++++++++++++ .../commands/kubernetes/traits/model/Traits.java | 16 ++- .../commands/kubernetes/KubernetesExportTest.java | 45 +++++++++ 7 files changed, 442 insertions(+), 1 deletion(-) diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc index 58aec45a7f7..974d61425bc 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-kubernetes.adoc @@ -1222,6 +1222,110 @@ spec: <6> Service Resource reference +=== Jolokia trait options + +The Jolokia trait enhances the Kubernetes manifest enabling JMX access to Camel application. This requires jolokia being configured in the Camel Application. + +The Jolokia trait provides the following configuration options: + +[cols="2m,1m,5a"] +|=== +|Property | Type | Description + +| jolokia.enabled +| bool +| Can be used to enable or disable a trait. All traits share this common property. (default `false`). + +| jolokia.container-port +| int +| To configure a different jolokia port exposed by the container (default `8778`). + +| jolokia.container-port-name +| string +| To configure a different port name for the port exposed by the container (default `jolokia`). + +| jolokia.expose +| bool +| Can be used to enable/disable exposure of jolokia via kubernetes Service. (default `false`). + +| jolokia.service-port +| int +| To configure a different jolokia port exposed by the service (default `8778`). It is applied only when the expose parameter is true. + +| jolokia.service-port-name +| string +| To configure a different port name for the port exposed by the service (default `jolokia`). It is applied only when the expose parameter is true. + + +|=== + +The syntax to specify jolokia trait options is as follows: + +[source,bash] +---- +camel kubernetes export Sample.java --trait jolokia.[key]=[value] +---- + +You may specify these options with the export command to customize the Container and Service Resource specification for Jolokia. + +[source,bash] +---- +camel kubernetes export Sample.java --trait jolokia.enabled=true --trait jolokia.container-port=8779 --trait jolokia.container-port-name=jolokia-port --trait jolokia.expose=true --trait jolokia.service-port=8779 --trait jolokia.service-port-name=port-jolokia +---- + +This results in the following specifications in the Deployment and Service resources. + +[source,yaml] +---- +apiVersion: apps/v1 +kind: Deployment +metadata: + ... + name: sample +spec: + selector: + ... + template: + ... + spec: + containers: + - name: sample + ports: + - containerPort: 8080 + name: http + protocol: TCP + - containerPort: 8779 #<1> + name: jolokia-port #<2> + protocol: TCP +... +---- + +[source,yaml] +---- +apiVersion: v1 +kind: Service +metadata: +... + name: sample +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http + - name: jolokia-port #<3> + port: 8779 #<4> + protocol: TCP + targetPort: jolokia-port #<2> +... +---- + +<1> Custom Jolokia container port +<2> Custom Jolokia container port name +<3> Custom Jolokia service port name +<4> Custom Jolokia service port + + === OpenApi specifications You can mount OpenAPI specifications to the application container with this trait. diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/JolokiaTrait.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/JolokiaTrait.java new file mode 100644 index 00000000000..aeaa97ded51 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/JolokiaTrait.java @@ -0,0 +1,93 @@ +/* + * 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.kubernetes.traits; + +import java.util.Optional; + +import io.fabric8.kubernetes.api.model.IntOrString; +import org.apache.camel.dsl.jbang.core.commands.kubernetes.traits.model.Jolokia; +import org.apache.camel.dsl.jbang.core.commands.kubernetes.traits.model.Traits; + +public class JolokiaTrait extends BaseTrait { + public static final int JolokiaTrait = 1800; + + public static final int DEFAULT_JOLOKIA_PORT = 8778; + public static final String DEFAULT_JOLOKIA_PORT_NAME = "jolokia"; + public static final String DEFAULT_JOLOKIA_PORT_PROTOCOL = "TCP"; + + public JolokiaTrait() { + super("jolokia", JolokiaTrait); + } + + @Override + public boolean configure(Traits traitConfig, TraitContext context) { + // must be explicitly enabled + if (traitConfig.getJolokia() == null) { + return false; + } else { + return Optional.ofNullable(traitConfig.getJolokia().getEnabled()).orElse(false); + } + } + + @Override + public void apply(Traits traitConfig, TraitContext context) { + Jolokia jolokiaTrait = Optional.ofNullable(traitConfig.getJolokia()).orElseGet(Jolokia::new); + + context.doWithDeployments( + d -> d.editSpec() + .editTemplate() + .editSpec() + .editFirstContainer() + .addNewPort() + .withName(Optional.ofNullable(jolokiaTrait.getContainerPortName()).orElse(DEFAULT_JOLOKIA_PORT_NAME)) + .withContainerPort(Optional.ofNullable(jolokiaTrait.getContainerPort()).map(Long::intValue) + .orElse(DEFAULT_JOLOKIA_PORT)) + .withProtocol(DEFAULT_JOLOKIA_PORT_PROTOCOL) + .endPort() + .endContainer() + .endSpec() + .endTemplate() + .endSpec()); + context.doWithKnativeServices( + s -> s.editSpec() + .editTemplate() + .editSpec() + .editFirstContainer() + .addNewPort() + .withName(Optional.ofNullable(jolokiaTrait.getContainerPortName()).orElse(DEFAULT_JOLOKIA_PORT_NAME)) + .withContainerPort(Optional.ofNullable(jolokiaTrait.getContainerPort()).map(Long::intValue) + .orElse(DEFAULT_JOLOKIA_PORT)) + .withProtocol(DEFAULT_JOLOKIA_PORT_PROTOCOL) + .endPort() + .endContainer() + .endSpec() + .endTemplate() + .endSpec()); + context.doWithServices( + s -> s.editSpec() + .addNewPort() + .withName(Optional.ofNullable(jolokiaTrait.getServicePortName()).orElse(DEFAULT_JOLOKIA_PORT_NAME)) + .withPort(Optional.ofNullable(jolokiaTrait.getServicePort()).map(Long::intValue) + .orElse(DEFAULT_JOLOKIA_PORT)) + .withTargetPort(new IntOrString( + Optional.ofNullable(jolokiaTrait.getContainerPortName()).orElse(DEFAULT_JOLOKIA_PORT_NAME))) + .endPort() + .endSpec()); + + } + +} diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitCatalog.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitCatalog.java index d6205b5686a..0a491f818aa 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitCatalog.java +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/TraitCatalog.java @@ -51,6 +51,7 @@ public class TraitCatalog { register(new LabelTrait()); register(new AnnotationTrait()); register(new CamelTrait()); + register(new JolokiaTrait()); } public List<Trait> allTraits() { diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/Jolokia.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/Jolokia.java new file mode 100644 index 00000000000..8927bb95451 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/Jolokia.java @@ -0,0 +1,110 @@ +/* + * 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.kubernetes.traits.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "enabled", "containerPort", "containerPortName", "expose", "servicePort", "servicePortName" }) +public class Jolokia { + @JsonProperty("enabled") + @JsonPropertyDescription("Can be used to enable or disable a trait.") + @JsonSetter(nulls = Nulls.SKIP) + private Boolean enabled; + @JsonProperty("containerPort") + @JsonPropertyDescription("To configure a different jolokia port exposed by the container (default `8778`).") + @JsonSetter( + nulls = Nulls.SKIP) + private Long containerPort; + @JsonProperty("containerPortName") + @JsonPropertyDescription("To configure a different jolokia port name for the port exposed by the container. It defaults to `jolokia`.") + @JsonSetter( + nulls = Nulls.SKIP) + private String containerPortName; + @JsonProperty("expose") + @JsonPropertyDescription("Can be used to enable/disable jolokia exposure via kubernetes Service. Requires Service to be enabled to be applicable.") + @JsonSetter( + nulls = Nulls.SKIP) + private Boolean expose; + @JsonProperty("servicePort") + @JsonPropertyDescription("To configure a different jolokia port exposed by the service (default `8778`).") + @JsonSetter( + nulls = Nulls.SKIP) + private Long servicePort; + @JsonProperty("servicePortName") + @JsonPropertyDescription("To configure a different jolokia port name for the port exposed by the service. It defaults to `jolokia`.") + @JsonSetter( + nulls = Nulls.SKIP) + private String servicePortName; + + public Jolokia() { + } + + public Boolean getEnabled() { + return this.enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Long getContainerPort() { + return this.containerPort; + } + + public void setContainerPort(Long port) { + this.containerPort = port; + } + + public String getContainerPortName() { + return this.containerPortName; + } + + public void setContainerPortName(String portName) { + this.containerPortName = portName; + } + + public Boolean getExpose() { + return this.expose; + } + + public void setExpose(Boolean expose) { + this.expose = expose; + } + + public Long getServicePort() { + return this.servicePort; + } + + public void setServicePort(Long port) { + this.servicePort = port; + } + + public String getServicePortName() { + return this.servicePortName; + } + + public void setServicePortName(String portName) { + this.servicePortName = portName; + } +} diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/JolokiaBuilder.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/JolokiaBuilder.java new file mode 100644 index 00000000000..5b3864875b5 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/JolokiaBuilder.java @@ -0,0 +1,74 @@ +/* + * 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.kubernetes.traits.model; + +public final class JolokiaBuilder { + private Boolean enabled; + private Long containerPort; + private String containerPortName; + private Boolean expose; + private Long servicePort; + private String servicePortName; + + private JolokiaBuilder() { + } + + public static JolokiaBuilder jolokia() { + return new JolokiaBuilder(); + } + + public JolokiaBuilder withEnabled(Boolean enabled) { + this.enabled = enabled; + return this; + } + + public JolokiaBuilder withContainerPort(Long port) { + this.containerPort = port; + return this; + } + + public JolokiaBuilder withContainerPortName(String portName) { + this.containerPortName = portName; + return this; + } + + public JolokiaBuilder withExpose(Boolean expose) { + this.expose = expose; + return this; + } + + public JolokiaBuilder withServicePort(Long port) { + this.servicePort = port; + return this; + } + + public JolokiaBuilder withServicePortName(String portName) { + this.servicePortName = portName; + return this; + } + + public Jolokia build() { + Jolokia jolokia = new Jolokia(); + jolokia.setEnabled(enabled); + jolokia.setContainerPort(containerPort); + jolokia.setContainerPortName(containerPortName); + jolokia.setExpose(expose); + jolokia.setServicePort(servicePort); + jolokia.setServicePortName(servicePortName); + return jolokia; + } +} diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/Traits.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/Traits.java index 88e15c7f51e..512f53fe37b 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/Traits.java +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/traits/model/Traits.java @@ -29,7 +29,7 @@ import com.fasterxml.jackson.annotation.Nulls; @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "camel", "container", "environment", "ingress", "knative", "knative-service", "mount", "openapi", "pod", "route", - "service", "service-binding" }) + "service", "service-binding", "jolokia" }) public class Traits { @JsonProperty("addons") @@ -86,11 +86,17 @@ public class Traits { @JsonPropertyDescription("The configuration of Service trait") @JsonSetter(nulls = Nulls.SKIP) private Service service; + @JsonProperty("service-binding") @JsonPropertyDescription("The configuration of Service Binding trait") @JsonSetter(nulls = Nulls.SKIP) private ServiceBinding serviceBinding; + @JsonProperty("jolokia") + @JsonPropertyDescription("The configuration of Jolokia trait") + @JsonSetter(nulls = Nulls.SKIP) + private Jolokia jolokia; + public Map<String, Addons> getAddons() { return this.addons; } @@ -171,6 +177,14 @@ public class Traits { this.route = route; } + public Jolokia getJolokia() { + return jolokia; + } + + public void setJolokia(Jolokia jolokia) { + this.jolokia = jolokia; + } + public Service getService() { return service; } diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java index 97db5fa3106..af3a2083f74 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java @@ -628,4 +628,49 @@ class KubernetesExportTest extends KubernetesExportBaseTest { Assertions.assertEquals("quay.io/camel/demo-app:1.0", props.get("jkube.image.name")); Assertions.assertEquals("quay.io/camel/demo-app:1.0", props.get("jkube.container-image.name")); } + + @ParameterizedTest + @MethodSource("runtimeProvider") + public void shouldAddJolokiaSpec(RuntimeType rt) throws Exception { + KubernetesExport command = createCommand(new String[] { "classpath:route-service.yaml" }, + "--trait", "jolokia.enabled=true", + "--trait", "jolokia.expose=true", + "--trait", "jolokia.service-port=8779", + "--trait", "jolokia.service-port-name=jolokia-port", + "--runtime=" + rt.runtime()); + var exit = command.doCall(); + Assertions.assertEquals(0, exit); + + Assertions.assertTrue(hasService(rt)); + Assertions.assertFalse(hasKnativeService(rt)); + + Deployment deployment = getDeployment(rt); + Container container = deployment.getSpec().getTemplate().getSpec().getContainers().get(0); + Assertions.assertEquals("route-service", deployment.getMetadata().getName()); + Assertions.assertEquals(1, deployment.getSpec().getTemplate().getSpec().getContainers().size()); + Assertions.assertNull(container.getImage()); + Assertions.assertEquals(2, container.getPorts().size()); + Assertions.assertEquals("jolokia", container.getPorts().get(1).getName()); + Assertions.assertEquals(8778, container.getPorts().get(1).getContainerPort()); + + Model model = readMavenModel(); + Assertions.assertEquals("org.example.project", model.getGroupId()); + Assertions.assertEquals("route-service", model.getArtifactId()); + Assertions.assertEquals("1.0-SNAPSHOT", model.getVersion()); + + Properties props = model.getProperties(); + Assertions.assertEquals("route-service:1.0-SNAPSHOT", props.get("jkube.image.name")); + Assertions.assertEquals("route-service:1.0-SNAPSHOT", props.get("jkube.container-image.name")); + + Service service = getService(rt); + List<ServicePort> ports = service.getSpec().getPorts(); + Assertions.assertEquals("route-service", service.getMetadata().getName()); + Assertions.assertEquals(2, ports.size()); + Assertions.assertEquals("http", ports.get(0).getName()); + Assertions.assertEquals(80, ports.get(0).getPort()); + Assertions.assertEquals("http", ports.get(0).getTargetPort().getStrVal()); + Assertions.assertEquals("jolokia-port", ports.get(1).getName()); + Assertions.assertEquals(8779, ports.get(1).getPort()); + Assertions.assertEquals("jolokia", ports.get(1).getTargetPort().getStrVal()); + } }