Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.15.x midstream backports #418

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions integration-tests-support/splunk/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
=== Development information

* `Security` If no custom certificate is provided, splunk server creates its own one and the `SplunkTestResource` copies it from the container into `test-classes`
* `Security` Server certificate has to be signed (that is the reason of using keytool in the pom.xml)
* `Security` SSL connection can be verified by openssl tool
```
openssl s_client -connect localhost:32825 -CAfile cacert.pem
```
* `Security` Server certificate has to contain a private key, which could not be done via keytool itself. Proper way of achieving such certificate is to use Openssl tool. The `TestResource` is concatenating certificates and keys programmatically.
```
openssl pkcs12 -export -out combined.p12 -inkey localhost-key.pem -in localhost.pem -certfile splunkca.pem
openssl pkcs12 -in combined.p12 -out combined.pem -nodes
```
* Set log level to debug for `org.apache.camel.quarkus.test.support.splunk` (by adding `quarkus.log.category.\"org.apache.camel.quarkus.test.support.splunk\".level=DEBUG` into application.properties) to see more important information from runtime.
* `TestResource` is exporting configuration files, log and certificates to the `test-classes` folder.
* Splunk server takes a lot of time to start. It might be handy to start a test with a different process with some timeout (like several hours) and use FakeSplunkTestResource with hardcoded ports.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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.quarkus.test.support.splunk;

import java.util.Map;

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.apache.commons.lang3.StringUtils;

/**
* Test Resource meant for development. Replace port numbers with the real ports of the container running in different
* process.
* See README.adoc for more hints.
*/
public class FakeSplunkTestResource implements QuarkusTestResourceLifecycleManager {

@Override
public Map<String, String> start() {

String banner = StringUtils.repeat("*", 50);

Map<String, String> m = Map.of(
SplunkConstants.PARAM_REMOTE_HOST, "localhost",
SplunkConstants.PARAM_TCP_PORT, "328854",
SplunkConstants.PARAM_HEC_TOKEN, "TESTTEST-TEST-TEST-TEST-TESTTESTTEST",
SplunkConstants.PARAM_TEST_INDEX, SplunkTestResource.TEST_INDEX,
SplunkConstants.PARAM_REMOTE_PORT, "32885",
SplunkConstants.PARAM_HEC_PORT, "32886");

return m;

}

@Override
public void stop() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,36 @@
*/
package org.apache.camel.quarkus.test.support.splunk;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.time.Duration;
import java.util.Base64;
import java.util.Map;
import java.util.TimeZone;
import java.util.stream.Collectors;

import io.quarkus.logging.Log;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.Container;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.images.builder.Transferable;
import org.testcontainers.utility.MountableFile;

public class SplunkTestResource implements QuarkusTestResourceLifecycleManager {

Expand All @@ -36,12 +56,28 @@ public class SplunkTestResource implements QuarkusTestResourceLifecycleManager {
private static final int REMOTE_PORT = 8089;
private static final int WEB_PORT = 8000;
private static final int HEC_PORT = 8088;
private static final Logger LOG = Logger.getLogger(SplunkTestResource.class);
private static final Logger LOG = LoggerFactory.getLogger(SplunkTestResource.class);

private GenericContainer<?> container;

private String localhostCertPath;
private String localhostKeystorePath;
private String caCertPath;
private String keystorePassword;

@Override
public void init(Map<String, String> initArgs) {
localhostCertPath = initArgs.get("localhost_cert");
caCertPath = initArgs.get("ca_cert");
localhostKeystorePath = initArgs.get("localhost_keystore");
keystorePassword = initArgs.get("keystore_password");
}

@Override
public Map<String, String> start() {

String banner = StringUtils.repeat("*", 50);

try {
container = new GenericContainer<>(SPLUNK_IMAGE_NAME)
.withExposedPorts(REMOTE_PORT, SplunkConstants.TCP_PORT, WEB_PORT, HEC_PORT)
Expand All @@ -54,41 +90,137 @@ public Map<String, String> start() {
Wait.forLogMessage(".*Ansible playbook complete.*\\n", 1)
.withStartupTimeout(Duration.ofMinutes(5)));

if (localhostCertPath != null && localhostKeystorePath != null && caCertPath != null && keystorePassword != null) {
//combine key + certificates into 1 pem - required for splunk
//extraction of private key can not be done by keytool (only openssl), but it can be done programmatically
byte[] concatenate = concatenateKeyAndCertificates(banner);

container.withCopyToContainer(Transferable.of(concatenate), "/opt/splunk/etc/auth/mycerts/myServerCert.pem")
.withCopyToContainer(Transferable.of(Files.readAllBytes(Paths.get(caCertPath))),
"/opt/splunk/etc/auth/mycerts/cacert.pem");
} else {
LOG.debug("Internal certificates are used for Splunk server.");
}

container.start();

container.execInContainer("sudo", "sed", "-i", "s/allowRemoteLogin=requireSetPassword/allowRemoteLogin=always/",
"/opt/splunk/etc/system/default/server.conf");
container.execInContainer("sudo", "sed", "-i", "s/enableSplunkdSSL = true/enableSplunkdSSL = false/",
"/opt/splunk/etc/system/default/server.conf");
container.copyFileToContainer(MountableFile.forClasspathResource("local_server.conf"),
"/opt/splunk/etc/system/local/server.conf");
container.copyFileToContainer(MountableFile.forClasspathResource("local_inputs.conf"),
"/opt/splunk/etc/system/local/inputs.conf");

container.copyFileToContainer(MountableFile.forClasspathResource("local_server.conf"),
"/opt/splunk/etc/system/local/server.conf");
container.copyFileToContainer(MountableFile.forClasspathResource("local_inputs.conf"),
"/opt/splunk/etc/system/local/inputs.conf");

container.execInContainer("sudo", "sed", "-i", "s/minFreeSpace = 5000/minFreeSpace = 100/",
"/opt/splunk/etc/system/default/server.conf");
"/opt/splunk/etc/system/local/server.conf");

/* uncomment for troubleshooting purposes - copy configuration from container
container.copyFileFromContainer("/opt/splunk/etc/system/local/server.conf",
Path.of(getClass().getResource("/").getPath()).resolve("local_server_from_container.conf").toFile()
.getAbsolutePath());*/

container.execInContainer("sudo", "microdnf", "--nodocs", "update", "tzdata");//install tzdata package so we can specify tz other than UTC
assertExecResult(container.execInContainer("sudo", "microdnf", "--nodocs", "update", "tzdata"), "tzdata install");//install tzdata package so we can specify tz other than UTC

LOG.debug(banner);
LOG.debug("Restarting splunk server.");
LOG.debug(banner);

assertExecResult(container.execInContainer("sudo", "./bin/splunk", "restart"), "splunk restart");

container.execInContainer("sudo", "./bin/splunk", "restart");
container.execInContainer("sudo", "./bin/splunk", "add", "index", TEST_INDEX);
container.execInContainer("sudo", "./bin/splunk", "add", "tcp", String.valueOf(SplunkConstants.TCP_PORT),
"-sourcetype", "TCP");

String splunkHost = container.getHost();
/*uncomment for troubleshooting purposes - copy from container conf and log files
container.copyFileFromContainer("/opt/splunk/etc/system/local/server.conf",
Path.of(getClass().getResource("/").getPath()).resolve("local-server-from-container.conf").toFile()
.getAbsolutePath());
container.copyFileFromContainer("/opt/splunk/etc/system/default/server.conf",
Path.of(getClass().getResource("/").getPath()).resolve("default-server-from-container.log").toFile()
.getAbsolutePath());
if (localhostCertPath != null && localhostKeystorePath != null && caCertPath != null && keystorePassword != null) {
container.copyFileFromContainer("/opt/splunk/etc/auth/mycerts/myServerCert.pem",
Path.of(getClass().getResource("/").getPath()).resolve("myServerCert-from-container.pem").toFile()
.getAbsolutePath());
container.copyFileFromContainer("/opt/splunk/etc/auth/mycerts/cacert.pem",
Path.of(getClass().getResource("/").getPath()).resolve("cacert-from-container.pem").toFile()
.getAbsolutePath());
} else {
container.copyFileFromContainer("/opt/splunk/etc/auth/server.pem",
Path.of(getClass().getResource("/").getPath()).resolve("myServerCert-from-container.pem").toFile()
.getAbsolutePath());
container.copyFileFromContainer("/opt/splunk/etc/auth/cacert.pem",
Path.of(getClass().getResource("/").getPath()).resolve("cacert-from-container.pem").toFile()
.getAbsolutePath());
}
*/

String banner = StringUtils.repeat("*", 50);
LOG.info(banner);
LOG.infof("Splunk UI running on: http://%s:%d", splunkHost, container.getMappedPort(WEB_PORT));
LOG.info(banner);
String splunkHost = container.getHost();

return Map.of(
Map<String, String> m = Map.of(
SplunkConstants.PARAM_REMOTE_HOST, splunkHost,
SplunkConstants.PARAM_TCP_PORT, container.getMappedPort(SplunkConstants.TCP_PORT).toString(),
SplunkConstants.PARAM_HEC_TOKEN, HEC_TOKEN,
SplunkConstants.PARAM_TEST_INDEX, TEST_INDEX,
SplunkConstants.PARAM_REMOTE_PORT, container.getMappedPort(REMOTE_PORT).toString(),
SplunkConstants.PARAM_HEC_PORT, container.getMappedPort(HEC_PORT).toString());

LOG.info(banner);
LOG.info(String.format("Splunk UI running on: http://%s:%d", splunkHost, container.getMappedPort(WEB_PORT)));
LOG.info(banner);
LOG.debug(m.entrySet().stream().map(e -> e.getKey() + ": " + e.getValue()).sorted()
.collect(Collectors.joining("\n")));
LOG.debug(banner);

return m;

} catch (Exception e) {
throw new RuntimeException(e);
}
}

private byte @NotNull [] concatenateKeyAndCertificates(String banner)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
// Load the KeyStore
KeyStore keystore = KeyStore.getInstance("JKS");
try (FileInputStream fis = new FileInputStream(
Paths.get(localhostKeystorePath).toFile())) {
keystore.load(fis, keystorePassword.toCharArray());
}
// Get the private key
Key key = keystore.getKey(keystore.aliases().asIterator().next(), keystorePassword.toCharArray());

// Encode the private key to PEM format
String encodedKey = Base64.getEncoder().encodeToString(key.getEncoded());
String pemKey = "-----BEGIN PRIVATE KEY-----\n" + encodedKey + "\n-----END PRIVATE KEY-----";

//localhost.pem and cacert.pem has to be concatenated
String localhost = Files.readString(
Paths.get(localhostCertPath),
StandardCharsets.UTF_8);
String ca = Files.readString(Path.of(caCertPath),
StandardCharsets.UTF_8);
Log.debug("cacert content:");
Log.debug(ca);
Log.debug(banner);
byte[] concatenate = (localhost + ca + pemKey).getBytes(StandardCharsets.UTF_8);
return concatenate;
}

private static void assertExecResult(Container.ExecResult res, String cmd) {
if (res.getExitCode() != 0) {
LOG.error("Command: " + cmd);
LOG.error("Stdout: " + res.getStdout());
LOG.error("Stderr: " + res.getStderr());
throw new RuntimeException("Command " + cmd + ") failed. " + res.getStdout());
} else {
LOG.debug("Command: " + cmd + " succeeded!");
}
}

@Override
public void stop() {
try {
Expand Down
27 changes: 27 additions & 0 deletions integration-tests/smb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-direct</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-mock</artifactId>
Expand Down Expand Up @@ -71,6 +75,16 @@
<artifactId>quarkus-junit4-mock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-integration-test-support</artifactId>
Expand Down Expand Up @@ -115,6 +129,19 @@
</activation>
<dependencies>
<!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-direct-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-mock-deployment</artifactId>
Expand Down
Loading