Skip to content

Commit f6afddf

Browse files
[issues-85] New Apache Kafka related Tests
1 parent bead963 commit f6afddf

8 files changed

Lines changed: 1120 additions & 4 deletions
Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
/**
2+
* Copyright (C) 2026 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.jboss.intersmash.tests.wildfly.kafka;
17+
18+
import cz.xtf.core.openshift.OpenShifts;
19+
import io.fabric8.kubernetes.api.model.Secret;
20+
import io.fabric8.kubernetes.api.model.SecretVolumeSourceBuilder;
21+
import io.fabric8.kubernetes.api.model.VolumeBuilder;
22+
import io.fabric8.kubernetes.api.model.VolumeMountBuilder;
23+
import java.io.IOException;
24+
import java.util.ArrayList;
25+
import java.util.Arrays;
26+
import java.util.Base64;
27+
import java.util.Collections;
28+
import java.util.HashMap;
29+
import java.util.List;
30+
import java.util.Map;
31+
import java.util.stream.Collectors;
32+
import lombok.extern.slf4j.Slf4j;
33+
import org.assertj.core.util.Strings;
34+
import org.jboss.intersmash.IntersmashConfig;
35+
import org.jboss.intersmash.application.openshift.helm.HelmChartRelease;
36+
import org.jboss.intersmash.application.openshift.helm.WildflyHelmChartOpenShiftApplication;
37+
import org.jboss.intersmash.provision.helm.wildfly.WildflyHelmChartRelease;
38+
import org.jboss.intersmash.tests.wildfly.WildflyApplicationConfiguration;
39+
import org.jboss.intersmash.tests.wildfly.util.WildFlyHelmChartsConfiguration;
40+
41+
@Slf4j
42+
public class WildflyBootableJarGloballySecuredKafkaHelmApplication
43+
implements WildflyHelmChartOpenShiftApplication, WildflyApplicationConfiguration, WildFlyHelmChartsConfiguration {
44+
/** Application name used for labeling and resource identification. */
45+
public static final String APP_NAME = "mp-reactive-messaging-bjar";
46+
private static final String APP_MODULE_DIRECTORY = "wildfly/kafka-application";
47+
48+
private static final String CLIENT_SSL_CONTEXT_NAME = "kafka-ssl-test";
49+
private static final String SECRETS_VOLUME_MOUNT_PATH = "/etc/secrets";
50+
private static final String CERTIFICATE_SECRET_PATH = SECRETS_VOLUME_MOUNT_PATH + "/ca.p12";
51+
52+
/** List of Kubernetes secrets for keystores and truststores. */
53+
private final List<Secret> secrets = new ArrayList<>();
54+
55+
/** Helm chart release configuration for deploying the WildFly/JBoss EAP application. */
56+
private final HelmChartRelease release;
57+
58+
/**
59+
* Sets up the OpenShift namespace with required permissions for the WildFly/JBoss EAP application.
60+
* <p>
61+
* This method configures:
62+
* <ul>
63+
* <li>The 'view' role for the default service account (required for KUBE_PING clustering)</li>
64+
* </ul>
65+
* </p>
66+
* <p>
67+
* Without these permissions, JGroups clustering and the SAML adapter's route discovery
68+
* feature will not function properly.
69+
* </p>
70+
*
71+
* @throws IllegalStateException if the OpenShift commands fail to execute
72+
*/
73+
public static void setupNamespace() {
74+
// KUBE_PING requires this permission, otherwise warning is logged and clustering doesn't work,
75+
// an invalidation-cache requires a functioning jgroups cluster.
76+
log.debug("Adding role view to default service account...");
77+
OpenShifts.master().addRoleToServiceAccount("view", "default");
78+
}
79+
80+
/**
81+
* Constructs a new WildFly/JBoss EAP application configured with Keycloak SAML adapter.
82+
* <p>
83+
* This constructor initializes the application by:
84+
* <ul>
85+
* <li>Setting up the OpenShift namespace with required permissions</li>
86+
* <li>Loading and configuring the Helm chart release with build and deployment settings</li>
87+
* <li>Configuring environment variables for Keycloak integration</li>
88+
* </ul>
89+
* </p>
90+
*
91+
* @throws IOException if Helm chart configuration loading fails
92+
*/
93+
public WildflyBootableJarGloballySecuredKafkaHelmApplication() throws IOException {
94+
setupNamespace();
95+
release = loadRelease(getHelmChartRelease());
96+
}
97+
98+
/**
99+
* Loads and configures the Helm chart release for the WildFly/JBoss EAP application.
100+
* <p>
101+
* This method configures:
102+
* <ul>
103+
* <li>Build mode (Bootable JAR)</li>
104+
* <li>Source repository URL and reference</li>
105+
* <li>Maven build arguments and environment variables</li>
106+
* <li>Builder and runtime images</li>
107+
* <li>Build and deployment environment variables including Keycloak integration settings</li>
108+
* <li>Optional EE channel configuration for EAP builds</li>
109+
* </ul>
110+
* </p>
111+
*
112+
* @param release the WildFly Helm chart release to configure
113+
* @return the configured Helm chart release
114+
* @throws IOException if configuration loading fails
115+
*/
116+
private HelmChartRelease loadRelease(final WildflyHelmChartRelease release) throws IOException {
117+
// =======================================
118+
// WILDFLY HELM CHARTS
119+
// =======================================
120+
121+
// let's compute some additional maven args for our s2i build to happen on a Pod
122+
String mavenAdditionalArgs = "-Denforcer.skip=true";
123+
// let's add configurable deployment additional args:
124+
mavenAdditionalArgs = mavenAdditionalArgs.concat(generateAdditionalMavenArgs());
125+
// to speed up the build process we target a specific module; we also skip generating the "*-sources.jar" to disambiguate the S2I artifact to deploy (having both "*-sources.jar" and "*-bootable.jar" would fail the deployment)
126+
mavenAdditionalArgs = mavenAdditionalArgs.concat(" -Dmaven.source.skip -pl " + APP_MODULE_DIRECTORY + " -am ");
127+
128+
// =======================================
129+
// BUILD
130+
// =======================================
131+
132+
Map<String, String> buildEnvironmentVariables = new HashMap<>();
133+
final String mavenMirrorUrl = this.getMavenMirrorUrl();
134+
if (!Strings.isNullOrEmpty(mavenMirrorUrl)) {
135+
buildEnvironmentVariables.put("MAVEN_MIRROR_URL", mavenMirrorUrl);
136+
mavenAdditionalArgs = mavenAdditionalArgs.concat(" -Dinsecure.repositories=WARN");
137+
}
138+
139+
buildEnvironmentVariables.put("SCRIPT_DEBUG",
140+
IntersmashConfig.scriptDebug() != null ? IntersmashConfig.scriptDebug() : "false");
141+
buildEnvironmentVariables.put("LOGGING_SCRIPT_DEBUG",
142+
IntersmashConfig.scriptDebug() != null ? IntersmashConfig.scriptDebug() : "false");
143+
buildEnvironmentVariables.put("MAVEN_ARGS_APPEND", mavenAdditionalArgs);
144+
145+
// MAVEN_S2I_ARTIFACT_DIRS: tells S2I where to find artifacts to deploy (the "*-bootable.jar" file)
146+
buildEnvironmentVariables.put("MAVEN_S2I_ARTIFACT_DIRS", APP_MODULE_DIRECTORY + "/target");
147+
148+
// =======================================
149+
// DEPLOY
150+
// =======================================
151+
152+
Map<String, String> deploymentEnvironmentVariables = new HashMap<>();
153+
154+
deploymentEnvironmentVariables.put("SCRIPT_DEBUG",
155+
IntersmashConfig.scriptDebug() != null ? IntersmashConfig.scriptDebug() : "false");
156+
deploymentEnvironmentVariables.put("LOGGING_SCRIPT_DEBUG",
157+
IntersmashConfig.scriptDebug() != null ? IntersmashConfig.scriptDebug() : "false");
158+
159+
// =======================================
160+
// SECRET
161+
// =======================================
162+
163+
/**
164+
* Kafka secret is like:
165+
* {@code
166+
kind: Secret
167+
apiVersion: v1
168+
metadata:
169+
name: amq-streams-cluster-ca-cert
170+
data:
171+
ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZMVENDQXhXZ0F3SUJBZ0lVR01Cc3Fab ...
172+
ca.p12: MIIGogIBAzCCBkwGCSqGSIb3DQEHAaCCBj0EggY5MIIGNTCCBjEGCSqGSIb3DQEHBqCCBiIwg ...
173+
ca.password: b0QybzJ3T2czUUpm
174+
type: Opaque
175+
* }
176+
*/
177+
178+
Secret clientSecret = OpenShifts.master().getSecret("amq-streams-cluster-ca-cert");
179+
clientSecret.getMetadata().setName("client-amq-streams-cluster-ca-cert-secret");
180+
clientSecret.getMetadata().setResourceVersion(null);
181+
String password = new String(Base64.getDecoder().decode(clientSecret.getData().get("ca.password")));
182+
secrets.add(clientSecret);
183+
184+
// SSL
185+
deploymentEnvironmentVariables.put("KEYSTORE_PATH", CERTIFICATE_SECRET_PATH);
186+
deploymentEnvironmentVariables.put("KEYSTORE_PASSWORD", password);
187+
188+
// Configure the Elytron SSL context globally
189+
deploymentEnvironmentVariables.put("MP_MESSAGING_CONNECTOR_SMALLRYE_KAFKA_WILDFLY_ELYTRON_SSL_CONTEXT",
190+
CLIENT_SSL_CONTEXT_NAME);
191+
192+
// =======================================
193+
// APPLICATION
194+
// =======================================
195+
release
196+
// we explicitly set we need an s2i build, ot Bootable JAR, otherwise the OpenJDK image would be
197+
// used since the Bootable JAR mode is the default.
198+
.withBuildMode(WildflyHelmChartRelease.BuildMode.BOOTABLE_JAR)
199+
.withSourceRepositoryUrl(IntersmashConfig.deploymentsRepositoryUrl())
200+
.withSourceRepositoryRef(IntersmashConfig.deploymentsRepositoryRef())
201+
// TODO: check why jdk17 / jdk21 in `intersmash.bootable.jar.image=registry.access.redhat.com/ubi8/openjdk-17` and `intersmash.wildfly.image=quay.io/wildfly/wildfly-s2i:2.1.0-jdk21`
202+
.withJdk17BuilderImage(IntersmashConfig.wildflyImageURL())
203+
.withJdk17RuntimeImage(IntersmashConfig.wildflyRuntimeImageURL())
204+
.withBuildEnvironmentVariables(buildEnvironmentVariables)
205+
.withDeploymentEnvironmentVariables(deploymentEnvironmentVariables)
206+
.withVolume(
207+
new VolumeBuilder()
208+
.withName("client-amq-streams-cluster-ca-cert-secret")
209+
.withSecret(
210+
new SecretVolumeSourceBuilder()
211+
.withSecretName("client-amq-streams-cluster-ca-cert-secret")
212+
.build())
213+
.build())
214+
.withVolumeMount(
215+
new VolumeMountBuilder()
216+
.withName("client-amq-streams-cluster-ca-cert-secret")
217+
.withMountPath(SECRETS_VOLUME_MOUNT_PATH)
218+
.withReadOnly(true)
219+
.build());
220+
List<String> channelDefinition = Arrays.asList(this.eeChannelGroupId(), this.eeChannelArtifactId(),
221+
this.eeChannelVersion());
222+
if (!channelDefinition.isEmpty()) {
223+
// an example of EAP channel usage, not working with EAP 7.4.x or WildFly
224+
release.withS2iChannel(channelDefinition.stream().collect(Collectors.joining(":")));
225+
}
226+
227+
return release;
228+
}
229+
230+
/**
231+
* Returns the builder image URL for Source-to-Image builds.
232+
*
233+
* @return the WildFly/JBoss EAP builder image URL
234+
*/
235+
@Override
236+
public String getBuilderImage() {
237+
return IntersmashConfig.wildflyImageURL();
238+
}
239+
240+
/**
241+
* Returns the runtime image URL for the Bootable JAR deployment.
242+
*
243+
* @return the WildFly/JBoss EAP runtime image URL
244+
*/
245+
@Override
246+
public String getRuntimeImage() {
247+
return IntersmashConfig.wildflyRuntimeImageURL();
248+
}
249+
250+
/**
251+
* Returns the configured Helm chart release.
252+
*
253+
* @return the Helm chart release configuration
254+
*/
255+
@Override
256+
public HelmChartRelease getRelease() {
257+
return release;
258+
}
259+
260+
/**
261+
* Returns the Helm charts repository URL.
262+
*
263+
* @return the WildFly Helm charts repository URL
264+
*/
265+
@Override
266+
public String getHelmChartsRepositoryUrl() {
267+
return IntersmashConfig.getWildflyHelmChartsRepo();
268+
}
269+
270+
/**
271+
* Returns the Helm charts repository reference (branch or tag).
272+
*
273+
* @return the WildFly Helm charts repository reference
274+
*/
275+
@Override
276+
public String getHelmChartsRepositoryRef() {
277+
return IntersmashConfig.getWildflyHelmChartsBranch();
278+
}
279+
280+
/**
281+
* Returns the Helm charts repository name.
282+
*
283+
* @return the WildFly Helm charts repository name
284+
*/
285+
@Override
286+
public String getHelmChartsRepositoryName() {
287+
return IntersmashConfig.getWildflyHelmChartsName();
288+
}
289+
290+
/**
291+
* Returns an unmodifiable list of Kubernetes secrets.
292+
* <p>
293+
* The secrets include:
294+
* <ul>
295+
* <li>SAML keystore for encryption and signing</li>
296+
* <li>HTTPS truststore for secure communication with Keycloak</li>
297+
* </ul>
298+
* </p>
299+
*
300+
* @return unmodifiable list of Kubernetes secrets
301+
*/
302+
@Override
303+
public List<Secret> getSecrets() {
304+
return Collections.unmodifiableList(secrets);
305+
}
306+
307+
/**
308+
* Returns the application name.
309+
*
310+
* @return the application name
311+
*/
312+
@Override
313+
public String getName() {
314+
return APP_NAME;
315+
}
316+
317+
/**
318+
* Returns the route to access the WildFly/JBoss EAP application.
319+
*
320+
* @return the WildFly/JBoss EAP application route hostname
321+
*/
322+
public static String getRoute() {
323+
return OpenShifts.master().generateHostname(APP_NAME);
324+
}
325+
}

0 commit comments

Comments
 (0)