diff --git a/core/src/main/java/org/jboss/intersmash/annotations/Intersmash.java b/core/src/main/java/org/jboss/intersmash/annotations/Intersmash.java index 6175b9c1a..32a3ab76b 100644 --- a/core/src/main/java/org/jboss/intersmash/annotations/Intersmash.java +++ b/core/src/main/java/org/jboss/intersmash/annotations/Intersmash.java @@ -23,6 +23,10 @@ import org.jboss.intersmash.junit5.IntersmashExtension; import org.junit.jupiter.api.extension.ExtendWith; +/** + * Annotation that is applied to a test class, so that the JUnit engine would use the {@link IntersmashExtension} to + * run the Intersmash provisioning workflow, and execute the related tests. + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @ExtendWith(IntersmashExtension.class) diff --git a/core/src/main/java/org/jboss/intersmash/annotations/Service.java b/core/src/main/java/org/jboss/intersmash/annotations/Service.java index 80797fc1d..5382629a7 100644 --- a/core/src/main/java/org/jboss/intersmash/annotations/Service.java +++ b/core/src/main/java/org/jboss/intersmash/annotations/Service.java @@ -23,6 +23,10 @@ import org.jboss.intersmash.application.Application; +/** + * Annotation to define an Intersmash service, i.e. the abstraction of a given runtime workload. + * Examples are: a WildFly application service, a Keycloak service etc. on OpenShift. + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Repeatable(Services.class) diff --git a/core/src/main/java/org/jboss/intersmash/annotations/Services.java b/core/src/main/java/org/jboss/intersmash/annotations/Services.java index 5e15d421a..147dade0e 100644 --- a/core/src/main/java/org/jboss/intersmash/annotations/Services.java +++ b/core/src/main/java/org/jboss/intersmash/annotations/Services.java @@ -20,6 +20,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Annotation to define a group of Intersmash {@link Service} instances. + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Services { diff --git a/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExecutionCondition.java b/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExecutionCondition.java index d08f9c506..98ccc1487 100644 --- a/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExecutionCondition.java +++ b/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExecutionCondition.java @@ -29,6 +29,10 @@ import cz.xtf.core.openshift.OpenShifts; import lombok.extern.slf4j.Slf4j; +/** + * Implements a JUnit {@link ExecutionCondition} that is used to control whether a test class workflow can be managed by + * {@link IntersmashExtension} + */ @Slf4j public class IntersmashExecutionCondition implements ExecutionCondition { diff --git a/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExtension.java b/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExtension.java index 1f4c722f6..32bec47df 100644 --- a/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExtension.java +++ b/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExtension.java @@ -47,6 +47,10 @@ import cz.xtf.core.openshift.OpenShifts; import lombok.extern.slf4j.Slf4j; +/** + * Intersmash JUnit extension that handles the process of provisioning a cross-product scenario before starting the + * test execution. + */ @Slf4j public class IntersmashExtension implements BeforeAllCallback, AfterAllCallback, TestInstancePostProcessor { diff --git a/core/src/main/java/org/jboss/intersmash/provision/Provisioner.java b/core/src/main/java/org/jboss/intersmash/provision/Provisioner.java index 2ceff6e72..283d60f49 100644 --- a/core/src/main/java/org/jboss/intersmash/provision/Provisioner.java +++ b/core/src/main/java/org/jboss/intersmash/provision/Provisioner.java @@ -20,7 +20,7 @@ import org.jboss.intersmash.application.Application; /** - * Application provisioner for deploying and undeploying the application. + * Application provisioner for deploying and undeploying a service, represented by a given {@link Application} instance. */ public interface Provisioner { diff --git a/core/src/main/java/org/jboss/intersmash/provision/ProvisionerFactory.java b/core/src/main/java/org/jboss/intersmash/provision/ProvisionerFactory.java index 4577ca7ef..235facd0c 100644 --- a/core/src/main/java/org/jboss/intersmash/provision/ProvisionerFactory.java +++ b/core/src/main/java/org/jboss/intersmash/provision/ProvisionerFactory.java @@ -17,6 +17,10 @@ import org.jboss.intersmash.application.Application; +/** + * Define the contract for classes that return a suitable {@link Provisioner} for a given {@link Application} class. + * @param The type of the {@link Provisioner} that the factory implementation shall return. + */ public interface ProvisionerFactory { /** diff --git a/core/src/main/java/org/jboss/intersmash/provision/ProvisionerManager.java b/core/src/main/java/org/jboss/intersmash/provision/ProvisionerManager.java index e21b81c32..e50678a63 100644 --- a/core/src/main/java/org/jboss/intersmash/provision/ProvisionerManager.java +++ b/core/src/main/java/org/jboss/intersmash/provision/ProvisionerManager.java @@ -19,8 +19,10 @@ import org.jboss.intersmash.application.Application; +/** + * Manager class to load the suitable {@link Provisioner} for a given {@link Application} instance, based on SPI. + */ public class ProvisionerManager { - /** * Get application provisioner based on interfaces the application does implement. * diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/FailFastUtils.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/FailFastUtils.java index 4429506da..3ac36412d 100644 --- a/core/src/main/java/org/jboss/intersmash/provision/openshift/FailFastUtils.java +++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/FailFastUtils.java @@ -22,6 +22,10 @@ import cz.xtf.core.waiting.failfast.FailFastBuilder; import cz.xtf.core.waiting.failfast.FailFastCheck; +/** + * Helper class that leverages the XTF library fail-fast APIs in methods that can be used to control the + * Intersmash provisioning workflow. + */ public class FailFastUtils { private static String[] failFastEventMessages = new String[] { "Failed to pull image.*", diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/OpenShiftUtils.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/OpenShiftUtils.java index 90cec8a26..2869009e4 100644 --- a/core/src/main/java/org/jboss/intersmash/provision/openshift/OpenShiftUtils.java +++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/OpenShiftUtils.java @@ -19,6 +19,10 @@ import cz.xtf.core.openshift.OpenShift; +/** + * Helper class that leverages the XTF library {@link OpenShift} APIs in methods that can be used to control the + * Intersmash provisioning workflow. + */ public class OpenShiftUtils { public static void deleteResourcesWithLabel(OpenShift openShift, String labelKey, String labelValue) { openShift.deploymentConfigs().withLabel(labelKey, labelValue).delete(); diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/WaitersUtil.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/WaitersUtil.java index 904eba2eb..49966871d 100644 --- a/core/src/main/java/org/jboss/intersmash/provision/openshift/WaitersUtil.java +++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/WaitersUtil.java @@ -28,6 +28,10 @@ import io.fabric8.kubernetes.api.model.EndpointSubset; import io.fabric8.kubernetes.api.model.Endpoints; +/** + * Helper class that leverages the XTF library {@link Waiter} APIs in methods that can be used to control the + * Intersmash provisioning workflow. + */ public class WaitersUtil { public static Waiter serviceEndpointsAreReady(OpenShift openShift, String serviceName, int numOfPods, Integer... ports) { return new SimpleWaiter(() -> { diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/CatalogSource.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/CatalogSource.java index 78e782fe1..e375d4b94 100644 --- a/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/CatalogSource.java +++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/CatalogSource.java @@ -17,6 +17,9 @@ import io.fabric8.openshift.api.model.operatorhub.v1alpha1.CatalogSourceBuilder; +/** + * Wrapper for creating and using {@link io.fabric8.openshift.api.model.operatorhub.v1alpha1.CatalogSource} + */ public class CatalogSource extends io.fabric8.openshift.api.model.operatorhub.v1alpha1.CatalogSource implements OpenShiftResource { diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/Subscription.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/Subscription.java index dfb3f8d96..db76c3cc6 100644 --- a/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/Subscription.java +++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/Subscription.java @@ -25,10 +25,9 @@ import io.fabric8.openshift.api.model.operatorhub.v1alpha1.SubscriptionFluent; /** - *

* The Subscription configures when and how to update a ClusterService, binds a ClusterService to a channel in a * CatalogSource and configures the update strategy for a ClusterService (automatic, manual approval, etc). - *

+ * *

This class is a wrapper for {@link io.fabric8.openshift.api.model.operatorhub.v1alpha1.Subscription} which * adds some capabilities

*

diff --git a/core/src/main/java/org/jboss/intersmash/util/CommandLineBasedKeystoreGenerator.java b/core/src/main/java/org/jboss/intersmash/util/CommandLineBasedKeystoreGenerator.java new file mode 100644 index 000000000..083653d37 --- /dev/null +++ b/core/src/main/java/org/jboss/intersmash/util/CommandLineBasedKeystoreGenerator.java @@ -0,0 +1,347 @@ +/** + * Copyright (C) 2023 Red Hat, Inc. + * + * Licensed 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.jboss.intersmash.util; + +import java.io.BufferedReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import cz.xtf.core.config.OpenShiftConfig; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/** + * CL based implementation of a class for generating keystores signed by one common generated Certification Authority + */ +@Slf4j +public class CommandLineBasedKeystoreGenerator { + public static final String KEYSTORE_FILE_EXTENSION = ".keystore"; + private static Path TMP_DIRECTORY = Paths.get("tmp").toAbsolutePath().resolve("keystores"); + @Getter + private static Path caDir; + @Getter + private static Path truststore; + @Getter + private static final String password = "password"; + private static final String INTERSMASH_CA = "Intersmash.ca"; + private static final String TRUSTSTORE_FILE_NAME = "truststore"; + public static final String CA_CERTIFICATE_PEM_FILE_NAME = "ca-certificate.pem"; + + /** + * Statically set everything up in order to have private key, certificate and truststore ready + */ + static { + try { + TMP_DIRECTORY.toFile().mkdirs(); + caDir = Files.createTempDirectory(TMP_DIRECTORY, "ca"); + // Generate key and cert + processCall(caDir, "openssl", + "req", + "-new", + "-newkey", + "rsa:4096", + "-x509", + "-keyout", + "ca-key.pem", + "-out", + CA_CERTIFICATE_PEM_FILE_NAME, + "-days", + "365", + "-passout", + "pass:" + password, + "-subj", + "/C=CZ/ST=CZ/L=Brno/O=QE/CN=" + INTERSMASH_CA); + // Generate truststore that includes the generated CA cert + processCall(caDir, "keytool", + "-import", + "-noprompt", + "-keystore", + TRUSTSTORE_FILE_NAME, + "-file", + CA_CERTIFICATE_PEM_FILE_NAME, + "-alias", + INTERSMASH_CA, + "-storepass", + password); + // Download and import the openshift server certs into the generated truststore + processCall(caDir, "/bin/sh", + "-c", + "echo \"Q\" | openssl s_client -connect " + getOpenShiftHostAndPort() + + " -showcerts 2>/dev/null > serversOpenSslResponse"); + processCall(caDir, "/bin/sh", + "-c", + getSplitCommandNameBasedOnOeratingSystem() + + " -f serverCert -s serversOpenSslResponse '/^-----BEGIN CERTIFICATE-----$/' '{*}'"); + processCall(caDir, "/bin/sh", + "-c", + "find . -type f -not -name \"serverCert00\" -name \"serverCert[0-9][0-9]\" -exec openssl x509 -in {} -out {}.pem \\;"); + processCall(caDir, "/bin/sh", + "-c", + "find . -type f -name \"serverCert[0-9][0-9].pem\" -exec keytool -import -noprompt -keystore " + + TRUSTSTORE_FILE_NAME + " -file {} -alias {} -storepass " + password + " \\;"); + truststore = caDir.resolve(TRUSTSTORE_FILE_NAME); + } catch (IOException e) { + throw new IllegalStateException("Failed to initialize Intersmash CA", e); + } + } + + public static Path generateKeystore(String hostname) { + return generateKeystore(hostname, null, hostname, false); + } + + public static Path generateKeystore(String hostname, String keyAlias) { + return generateKeystore(hostname, null, keyAlias, false); + } + + public static Path generateKeystore(String hostname, String keyAlias, boolean deleteCaFromKeyStore) { + return generateKeystore(hostname, null, keyAlias, deleteCaFromKeyStore); + } + + public static Path generateKeystore(String hostname, String[] alternativeHostnames) { + return generateKeystore(hostname, alternativeHostnames, hostname, false); + } + + public static Path generateKeystore(String hostname, String[] alternativeHostnames, String keyAlias, + boolean deleteCaFromKeyStore) { + final String keystore = hostname + KEYSTORE_FILE_EXTENSION; + if (caDir.resolve(keystore).toFile().exists()) { + return caDir.resolve(keystore); + } + processCall(caDir, "keytool", + "-genkeypair", + "-keyalg", + "RSA", + "-noprompt", + "-alias", + keyAlias, + "-dname", + "CN=" + hostname + ", OU=TF, O=XTF, L=Brno, S=CZ, C=CZ", + "-keystore", + keystore, + "-storepass", + password, + "-keypass", + password, + "-deststoretype", + "pkcs12"); + processCall(caDir, "keytool", + "-keystore", + keystore, + "-certreq", + "-alias", + keyAlias, + "--keyalg", + "rsa", + "-file", + hostname + ".csr", + "-storepass", + password); + // When provided, injects Subject Alternative Names (SAN) within the certificate + if (alternativeHostnames != null && alternativeHostnames.length > 0) { + try { + Writer writer = new FileWriter(caDir.resolve(keyAlias + ".extensions").toFile()); + writer.write("[ req_ext ]\n"); + writer.write("subjectAltName = @alt_names\n"); + writer.write("\n"); + writer.write("[ alt_names ]\n"); + + writer.write("DNS.1 = " + hostname + "\n"); + for (int i = 0; i < alternativeHostnames.length; ++i) { + writer.write("DNS." + (i + 2) + " = " + alternativeHostnames[i] + "\n"); + } + writer.flush(); + writer.close(); + processCall(caDir, "openssl", + "x509", + "-req", + "-CA", + CA_CERTIFICATE_PEM_FILE_NAME, + "-CAkey", + "ca-key.pem", + "-in", + hostname + ".csr", + "-out", hostname + ".cer", + "-days", "365", + "-CAcreateserial", + "-passin", + "pass:" + password, + "-extfile", + keyAlias + ".extensions", + "-extensions", + "req_ext"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else { + processCall(caDir, "openssl", + "x509", + "-req", + "-CA", + CA_CERTIFICATE_PEM_FILE_NAME, + "-CAkey", + "ca-key.pem", + "-in", + hostname + ".csr", + "-out", + hostname + ".cer", + "-days", + "365", + "-CAcreateserial", + "-passin", + "pass:" + password); + } + processCall(caDir, "keytool", + "-import", + "-noprompt", + "-keystore", + keystore, + "-file", + CA_CERTIFICATE_PEM_FILE_NAME, + "-alias", + INTERSMASH_CA, + "-storepass", + password); + processCall(caDir, "keytool", + "-import", + "-keystore", + keystore, + "-file", + hostname + ".cer", + "-alias", + keyAlias, + "-storepass", password); + if (deleteCaFromKeyStore) { + processCall(caDir, "keytool", + "-delete", + "-noprompt", + "-alias", INTERSMASH_CA, + "-keystore", + keystore, + "-storepass", + password); + } + return caDir.resolve(keystore); + } + + public static GeneratedPaths generateCerts(String hostname) { + return generateCerts(hostname, null); + } + + public static GeneratedPaths generateCerts(String hostname, String[] alternativeHostnames) { + final String keystore = hostname + KEYSTORE_FILE_EXTENSION; + generateKeystore(hostname, alternativeHostnames); + // export cert as CN.keystore.pem + processCall(caDir, "keytool", + "-exportcert", + "-rfc", + "-keystore", + keystore, + "-alias", + hostname, + "-storepass", + password, + "-file", + keystore + ".pem"); + // convert to CN.keystore.keywithattrs.pem + processCall(caDir, "openssl", + "pkcs12", + "-in", + keystore, + "-nodes", + "-nocerts", + "-out", + keystore + ".keywithattrs.pem", + "-passin", + "pass:" + password); + // Remove the Bag attributes to CN.keystore.key.pem + processCall(caDir, "openssl", + "rsa", + "-in", + keystore + ".keywithattrs.pem", + "-out", + keystore + ".key.pem"); + return new GeneratedPaths( + caDir.resolve(CA_CERTIFICATE_PEM_FILE_NAME), + caDir.resolve(TRUSTSTORE_FILE_NAME), + caDir.resolve(keystore), + caDir.resolve(keystore + ".key.pem"), + caDir.resolve(keystore + ".pem")); + } + + private static String getOpenShiftHostAndPort() { + String server = OpenShiftConfig.url().replaceFirst("https://", ""); + server = server.endsWith("/") ? server.substring(0, server.length() - 1) : server; + server = server.contains(":") ? server : server + ":443"; + return server; + } + + private static String getSplitCommandNameBasedOnOeratingSystem() { + return System.getProperty("os.name").toLowerCase().startsWith("mac") ? "gcsplit" : "csplit"; + } + + private static void processCall(Path cwd, String... args) { + ProcessBuilder pb = new ProcessBuilder(args); + + pb.directory(cwd.toFile()); + pb.redirectErrorStream(true); + + int result = -1; + Process process = null; + try { + process = pb.start(); + result = process.waitFor(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + while (reader.ready()) { + if (result == 0) { + log.debug(reader.readLine()); + } else { + log.error(reader.readLine()); + } + } + } + } catch (IOException | InterruptedException e) { + throw new IllegalStateException("Failed executing " + String.join(" ", args)); + } + if (result != 0) { + throw new IllegalStateException("Failed executing " + String.join(" ", args)); + } + } + + /** + * POJO to hold the path of the generated certs and stores + */ + public static class GeneratedPaths { + public Path caPem; + public Path truststore; + public Path keystore; + public Path keyPem; + public Path certPem; + + public GeneratedPaths(final Path caPem, final Path truststore, final Path keystore, final Path keyPem, + final Path certPem) { + this.caPem = caPem; + this.truststore = truststore; + this.keystore = keystore; + this.keyPem = keyPem; + this.certPem = certPem; + } + } +} diff --git a/core/src/main/java/org/jboss/intersmash/util/ProcessKeystoreGenerator.java b/core/src/main/java/org/jboss/intersmash/util/ProcessKeystoreGenerator.java deleted file mode 100644 index 59c517fa8..000000000 --- a/core/src/main/java/org/jboss/intersmash/util/ProcessKeystoreGenerator.java +++ /dev/null @@ -1,231 +0,0 @@ -/** - * Copyright (C) 2023 Red Hat, Inc. - * - * Licensed 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.jboss.intersmash.util; - -import java.io.BufferedReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Writer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import cz.xtf.core.config.OpenShiftConfig; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - -/** - * Class for generating keystores signed by one common generated ca - */ -@Slf4j -public class ProcessKeystoreGenerator { - - private static Path TMP_DIRECTORY = Paths.get("tmp").toAbsolutePath().resolve("keystores"); - - @Getter - private static Path caDir; - - @Getter - private static Path truststore; - - @Getter - private static final String password = "password"; - - static { - try { - TMP_DIRECTORY.toFile().mkdirs(); - caDir = Files.createTempDirectory(TMP_DIRECTORY, "ca"); - - // Generate key and cert - processCall(caDir, "openssl", "req", "-new", "-newkey", "rsa:4096", "-x509", "-keyout", "ca-key.pem", "-out", - "ca-certificate.pem", "-days", "365", "-passout", "pass:" + password, "-subj", - "/C=CZ/ST=CZ/L=Brno/O=QE/CN=xtf.ca"); - - // Generate truststore with ca cert - processCall(caDir, "keytool", "-import", "-noprompt", "-keystore", "truststore", "-file", "ca-certificate.pem", - "-alias", "xtf.ca", "-storepass", password); - - // Import openshift server certs to truststore - String server = OpenShiftConfig.url().replaceFirst("https://", ""); - server = server.endsWith("/") ? server.substring(0, server.length() - 1) : server; - server = server.contains(":") ? server : server + ":443"; - - processCall(caDir, "/bin/sh", "-c", - "echo \"Q\" | openssl s_client -connect " + server + " -showcerts 2>/dev/null > serversOpenSslResponse"); - String splitCmd = System.getProperty("os.name").toLowerCase().startsWith("mac") ? "gcsplit" : "csplit"; - processCall(caDir, "/bin/sh", "-c", - splitCmd + " -f serverCert -s serversOpenSslResponse '/^-----BEGIN CERTIFICATE-----$/' '{*}'"); - - processCall(caDir, "/bin/sh", "-c", - "find . -type f -not -name \"serverCert00\" -name \"serverCert[0-9][0-9]\" -exec openssl x509 -in {} -out {}.pem \\;"); - processCall(caDir, "/bin/sh", "-c", - "find . -type f -name \"serverCert[0-9][0-9].pem\" -exec keytool -import -noprompt -keystore truststore -file {} -alias {} -storepass " - + password + " \\;"); - - truststore = caDir.resolve("truststore"); - } catch (IOException e) { - throw new IllegalStateException("Failed to initialize CA", e); - } - } - - public static Path generateKeystore(String hostname) { - return generateKeystore(hostname, null, hostname, false); - } - - public static Path generateKeystore(String hostname, String keyAlias) { - return generateKeystore(hostname, null, keyAlias, false); - } - - public static Path generateKeystore(String hostname, String keyAlias, boolean deleteCaFromKeyStore) { - return generateKeystore(hostname, null, keyAlias, deleteCaFromKeyStore); - } - - public static Path generateKeystore(String hostname, String[] alternativeHostnames) { - return generateKeystore(hostname, alternativeHostnames, hostname, false); - } - - public static Path generateKeystore(String hostname, String[] alternativeHostnames, String keyAlias, - boolean deleteCaFromKeyStore) { - String keystore = hostname + ".keystore"; - - if (caDir.resolve(keystore).toFile().exists()) { - return caDir.resolve(keystore); - } - - processCall(caDir, "keytool", "-genkeypair", "-keyalg", "RSA", "-noprompt", "-alias", keyAlias, "-dname", - "CN=" + hostname + ", OU=TF, O=XTF, L=Brno, S=CZ, C=CZ", "-keystore", keystore, "-storepass", password, - "-keypass", password, "-deststoretype", "pkcs12"); - - processCall(caDir, "keytool", "-keystore", keystore, "-certreq", "-alias", keyAlias, "--keyalg", "rsa", "-file", - hostname + ".csr", "-storepass", password); - - if (alternativeHostnames != null && alternativeHostnames.length > 0) { - try { - Writer writer = new FileWriter(caDir.resolve(keyAlias + ".extensions").toFile()); - writer.write("[ req_ext ]\n"); - writer.write("subjectAltName = @alt_names\n"); - writer.write("\n"); - writer.write("[ alt_names ]\n"); - - writer.write("DNS.1 = " + hostname + "\n"); - for (int i = 0; i < alternativeHostnames.length; ++i) { - writer.write("DNS." + (i + 2) + " = " + alternativeHostnames[i] + "\n"); - } - writer.flush(); - writer.close(); - - processCall(caDir, "openssl", "x509", "-req", "-CA", "ca-certificate.pem", "-CAkey", "ca-key.pem", "-in", - hostname + ".csr", "-out", hostname + ".cer", "-days", "365", "-CAcreateserial", "-passin", - "pass:" + password, "-extfile", keyAlias + ".extensions", "-extensions", "req_ext"); - - } catch (IOException e) { - throw new RuntimeException(e); - } - } else { - processCall(caDir, "openssl", "x509", "-req", "-CA", "ca-certificate.pem", "-CAkey", "ca-key.pem", "-in", - hostname + ".csr", "-out", hostname + ".cer", "-days", "365", "-CAcreateserial", "-passin", - "pass:" + password); - } - - processCall(caDir, "keytool", "-import", "-noprompt", "-keystore", keystore, "-file", "ca-certificate.pem", "-alias", - "xtf.ca", "-storepass", password); - - processCall(caDir, "keytool", "-import", "-keystore", keystore, "-file", hostname + ".cer", "-alias", keyAlias, - "-storepass", password); - - if (deleteCaFromKeyStore) { - processCall(caDir, "keytool", "-delete", "-noprompt", "-alias", "xtf.ca", "-keystore", keystore, "-storepass", - password); - } - - return caDir.resolve(keystore); - } - - public static CertPaths generateCerts(String hostname) { - return generateCerts(hostname, null); - } - - public static CertPaths generateCerts(String hostname, String[] alternativeHostnames) { - String keystore = hostname + ".keystore"; - - generateKeystore(hostname, alternativeHostnames); - - // export cert as CN.keystore.pem - processCall(caDir, "keytool", "-exportcert", "-rfc", "-keystore", keystore, "-alias", hostname, "-storepass", password, - "-file", keystore + ".pem"); - - // convert to CN.keystore.keywithattrs.pem - processCall(caDir, "openssl", "pkcs12", "-in", keystore, "-nodes", "-nocerts", "-out", keystore + ".keywithattrs.pem", - "-passin", "pass:" + password); - - // Remove the Bag attributes to CN.keystore.key.pem - processCall(caDir, "openssl", "rsa", "-in", keystore + ".keywithattrs.pem", "-out", keystore + ".key.pem"); - - return new CertPaths( - caDir.resolve("ca-certificate.pem"), - caDir.resolve("truststore"), - caDir.resolve(keystore), - caDir.resolve(keystore + ".key.pem"), - caDir.resolve(keystore + ".pem")); - } - - private static void processCall(Path cwd, String... args) { - ProcessBuilder pb = new ProcessBuilder(args); - - pb.directory(cwd.toFile()); - pb.redirectErrorStream(true); - - int result = -1; - Process process = null; - try { - process = pb.start(); - result = process.waitFor(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { - while (reader.ready()) { - if (result == 0) { - log.debug(reader.readLine()); - } else { - log.error(reader.readLine()); - } - } - } - } catch (IOException | InterruptedException e) { - throw new IllegalStateException("Failed executing " + String.join(" ", args)); - } - - if (result != 0) { - throw new IllegalStateException("Failed executing " + String.join(" ", args)); - } - } - - public static class CertPaths { - - public Path caPem; - public Path truststore; - public Path keystore; - public Path keyPem; - public Path certPem; - - public CertPaths(Path caPem, Path truststore, Path keystore, Path keyPem, Path certPem) { - this.caPem = caPem; - this.truststore = truststore; - this.keystore = keystore; - this.keyPem = keyPem; - this.certPem = certPem; - } - } -} diff --git a/core/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory b/core/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory deleted file mode 100644 index 2ea1bd0ce..000000000 --- a/core/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory +++ /dev/null @@ -1 +0,0 @@ -org.jboss.intersmash.provision.openshift.auto.OpenShiftAutoProvisionerFactory diff --git a/provisioners/README.md b/provisioners/README.md index 8e32d4226..bf1fa97ec 100644 --- a/provisioners/README.md +++ b/provisioners/README.md @@ -245,7 +245,7 @@ Automatic (or application dictated) provisioning is a way to delegate the whole Having a concrete instance of an Application class that implements interface _AutoProvisioningOpenShiftApplication_ will let the user add methods that map to the provisioning process workflow, e.g.: `deploy`, `scale`, `undeploy`. -[OpenShiftAutoProvisionerFactory](../core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java) +[OpenShiftAutoProvisionerFactory](src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java) provides a reference to a _Provisioner_ and _Application_ implementing this feature. A list of provisioners by product can be found [here](../docs/Provisioner-by-Product.md). diff --git a/core/src/main/java/org/jboss/intersmash/application/auto/AutoProvisioningExecutionException.java b/provisioners/src/main/java/org/jboss/intersmash/application/auto/AutoProvisioningExecutionException.java similarity index 100% rename from core/src/main/java/org/jboss/intersmash/application/auto/AutoProvisioningExecutionException.java rename to provisioners/src/main/java/org/jboss/intersmash/application/auto/AutoProvisioningExecutionException.java diff --git a/core/src/main/java/org/jboss/intersmash/application/openshift/AutoProvisioningOpenShiftApplication.java b/provisioners/src/main/java/org/jboss/intersmash/application/openshift/AutoProvisioningOpenShiftApplication.java similarity index 100% rename from core/src/main/java/org/jboss/intersmash/application/openshift/AutoProvisioningOpenShiftApplication.java rename to provisioners/src/main/java/org/jboss/intersmash/application/openshift/AutoProvisioningOpenShiftApplication.java diff --git a/core/src/main/java/org/jboss/intersmash/provision/auto/AutoProvisioningManagedException.java b/provisioners/src/main/java/org/jboss/intersmash/provision/auto/AutoProvisioningManagedException.java similarity index 100% rename from core/src/main/java/org/jboss/intersmash/provision/auto/AutoProvisioningManagedException.java rename to provisioners/src/main/java/org/jboss/intersmash/provision/auto/AutoProvisioningManagedException.java diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisioner.java b/provisioners/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisioner.java similarity index 100% rename from core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisioner.java rename to provisioners/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisioner.java diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java b/provisioners/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java similarity index 100% rename from core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java rename to provisioners/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java diff --git a/provisioners/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory b/provisioners/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory index 5510c7640..95b263325 100644 --- a/provisioners/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory +++ b/provisioners/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory @@ -15,4 +15,5 @@ org.jboss.intersmash.provision.openshift.Eap7ImageOpenShiftProvisionerFactory org.jboss.intersmash.provision.openshift.Eap7LegacyS2iBuildTemplateProvisionerFactory org.jboss.intersmash.provision.openshift.Eap7TemplateOpenShiftProvisionerFactory org.jboss.intersmash.provision.openshift.HyperfoilOperatorProvisionerFactory +org.jboss.intersmash.provision.openshift.auto.OpenShiftAutoProvisionerFactory diff --git a/testsuite/integration-tests/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java b/testsuite/integration-tests/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java index 92df4de89..d8f778866 100644 --- a/testsuite/integration-tests/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java +++ b/testsuite/integration-tests/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java @@ -54,11 +54,10 @@ import org.jboss.intersmash.test.deployments.TestDeploymentProperties; import org.jboss.intersmash.test.deployments.WildflyDeploymentApplicationConfiguration; import org.jboss.intersmash.testsuite.IntersmashTestsuiteProperties; -import org.jboss.intersmash.util.ProcessKeystoreGenerator; +import org.jboss.intersmash.util.CommandLineBasedKeystoreGenerator; import org.jboss.intersmash.util.openshift.WildflyOpenShiftUtils; import org.jboss.intersmash.util.tls.CertificatesUtils; import org.jboss.intersmash.util.wildfly.Eap7CliScriptBuilder; -import org.keycloak.k8s.v2alpha1.Keycloak; import org.keycloak.k8s.v2alpha1.keycloakspec.HostnameBuilder; import org.keycloak.k8s.v2alpha1.keycloakspec.HttpBuilder; import org.keycloak.k8s.v2alpha1.keycloakspec.IngressBuilder; @@ -105,9 +104,9 @@ public class OpenShiftProvisionerTestBase { static RhSsoTemplateOpenShiftApplication getHttpsRhSso() { return new RhSsoTemplateOpenShiftApplication() { private final String secureAppHostname = "secure-" + getOpenShiftHostName(); - private final Path keystore = ProcessKeystoreGenerator.generateKeystore(secureAppHostname); + private final Path keystore = CommandLineBasedKeystoreGenerator.generateKeystore(secureAppHostname); private final String jceksFileName = "jgroups.jceks"; - private final Path truststore = ProcessKeystoreGenerator.getTruststore(); + private final Path truststore = CommandLineBasedKeystoreGenerator.getTruststore(); @Override public String getName() {