All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.quarkus.test.openshift.utils.OpenShiftPropertiesUtils Maven / Gradle / Ivy

package io.quarkus.test.openshift.utils;

import static io.quarkus.test.bootstrap.OpenShiftExtensionBootstrap.CLIENT;
import static io.quarkus.test.security.certificate.ServingCertificateConfig.isServingCertificateScenario;

import java.util.random.RandomGenerator;

import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Assertions;

import io.quarkus.test.bootstrap.Protocol;
import io.quarkus.test.bootstrap.ServiceContext;
import io.quarkus.test.bootstrap.inject.OpenShiftClient;
import io.quarkus.test.security.certificate.ServingCertificateConfig;
import io.quarkus.test.services.URILike;

public final class OpenShiftPropertiesUtils {

    public record PropertyToValue(String key, String value) {
    }

    public record PropertyToObj(String key, PropertyToValue value) {
    }

    public static final int EXTERNAL_SSL_PORT = 443;
    /**
     * ConfigMap name we use for OpenShift CA certificate injection.
     */
    public static final String CA_BUNDLE_CONFIGMAP_NAME = "ca-bundle-configmap";
    /**
     * Secret name we use for OpenShift serving certificates.
     */
    public static final String SERVING_CERTS_SECRET_NAME = "serving-certificates-secret";
    /**
     * Adds service annotation. Adding annotations is currently implemented for Quarkus runtimes only as that's what we
     * need. Supporting for all runtimes will require additional test that annotation is added to one service only.
     */
    private static final String ANNOTATION_PREFIX = "annotation::";
    /**
     * Separates annotation name and value.
     */
    private static final String ANNOTATION_SEPARATOR = "|";
    /**
     * Mounts existing secret. Mounting secrets is currently implemented for Quarkus runtimes only as that's what we
     * need. Supporting for all runtimes will require additional test that secret is mounted to one service only.
     */
    private static final String MOUNT_SECRET_PREFIX = "mount-secret::";
    /**
     * Separates secret name and mount path.
     */
    private static final String MOUNT_SECRET_SEPARATOR = "|";
    /**
     * Mounts existing configmap. Mounting configmaps is currently implemented for Quarkus runtimes only as that's
     * what we need. Supporting for all runtimes will require additional test that secret is mounted to one service only.
     */
    private static final String MOUNT_CONFIGMAP_PREFIX = "mount-configmap::";
    /**
     * Separates configmap name and mount path.
     */
    private static final String MOUNT_CONFIGMAP_SEPARATOR = "|";
    /**
     * Creates empty config map with annotation.
     */
    private static final String ANNOTATED_CONFIG_MAP_PREFIX = "annotated-configmap::";
    /**
     * Separates configmap name and annotation.
     */
    private static final String ANNOTATED_CONFIG_MAP_SEPARATOR = "|";
    /**
     * Separates configmap annotation key and value.
     */
    private static final String ANNOTATED_CONFIG_ANNOTATION_SEPARATOR = "&";
    private static final int INTERNAL_HTTPS_PORT_DEFAULT = 8443;
    private static final String QUARKUS_HTTPS_PORT_PROPERTY = "quarkus.http.ssl-port";

    private OpenShiftPropertiesUtils() {
        // utils
    }

    public static String buildAnnotatedConfigMapProp(String configmapName, String annotationKey, String annotationVal) {
        return ANNOTATED_CONFIG_MAP_PREFIX + configmapName + ANNOTATED_CONFIG_MAP_SEPARATOR + annotationKey
                + ANNOTATED_CONFIG_ANNOTATION_SEPARATOR + annotationVal;
    }

    public static String buildMountConfigMapProp(String secretName, String secretValue) {
        return MOUNT_CONFIGMAP_PREFIX + secretName + MOUNT_CONFIGMAP_SEPARATOR + secretValue;
    }

    public static String buildMountSecretProp(String secretName, String secretValue) {
        return MOUNT_SECRET_PREFIX + secretName + MOUNT_SECRET_SEPARATOR + secretValue;
    }

    public static String buildAnnotationProp(String annotationName, String annotationValue) {
        return ANNOTATION_PREFIX + annotationName + ANNOTATION_SEPARATOR + annotationValue;
    }

    public static boolean isMountSecret(String propertyValue) {
        return propertyValue.startsWith(MOUNT_SECRET_PREFIX);
    }

    public static boolean isMountConfigMap(String propertyValue) {
        return propertyValue.startsWith(MOUNT_CONFIGMAP_PREFIX);
    }

    public static boolean isAnnotatedConfigMap(String propertyValue) {
        return propertyValue.startsWith(ANNOTATED_CONFIG_MAP_PREFIX);
    }

    public static boolean isAnnotation(String propertyValue) {
        return propertyValue.startsWith(ANNOTATION_PREFIX);
    }

    public static String createAnnotationPropertyKey() {
        return createRandomPropertyKeyWithPrefix("annotation-");
    }

    public static String createSecretPropertyKey() {
        return createRandomPropertyKeyWithPrefix("secret-");
    }

    public static String createConfigMapPropertyKey() {
        return createRandomPropertyKeyWithPrefix("configmap-");
    }

    public static String createAnnotatedConfigMapPropertyKey() {
        return createRandomPropertyKeyWithPrefix("annotated-configmap-");
    }

    public static PropertyToValue getMountConfigMap(String propertyValue) {
        return getPropertyToValue(propertyValue, MOUNT_CONFIGMAP_PREFIX, MOUNT_CONFIGMAP_SEPARATOR, "configmap");
    }

    public static PropertyToValue getMountSecret(String propertyValue) {
        return getPropertyToValue(propertyValue, MOUNT_SECRET_PREFIX, MOUNT_SECRET_SEPARATOR, "secret");
    }

    public static PropertyToValue getServiceAnnotation(String propertyValue) {
        return getPropertyToValue(propertyValue, ANNOTATION_PREFIX, ANNOTATION_SEPARATOR, "annotation");
    }

    public static PropertyToObj getAnnotatedConfigMap(String propertyValue) {
        var configMapNameToAnnotation = getPropertyToValue(propertyValue, ANNOTATED_CONFIG_MAP_PREFIX,
                ANNOTATED_CONFIG_MAP_SEPARATOR, "annotated-configmap");
        var annotationKeyToValue = getPropertyToValue(configMapNameToAnnotation.value(), "",
                ANNOTATED_CONFIG_ANNOTATION_SEPARATOR, "annotation-configmap-annotation");
        return new PropertyToObj(configMapNameToAnnotation.key(), annotationKeyToValue);
    }

    public static boolean checkPodReadinessWithStatusInsteadOfRoute(ServiceContext ctx) {
        // using HTTPS & internal service URL & no exposed route => need to trust readiness
        return isServingCertificateScenario(ctx) && ServingCertificateConfig.get(ctx).addServiceCertificate();
    }

    public static int getInternalHttpsPort(ServiceContext ctx) {
        return ctx.getOwner().getProperty(QUARKUS_HTTPS_PORT_PROPERTY)
                .filter(StringUtils::isNotBlank)
                .map(Integer::parseInt)
                .orElse(INTERNAL_HTTPS_PORT_DEFAULT);
    }

    public static URILike getInternalServiceHttpsUrl(ServiceContext ctx) {
        var serviceName = ctx.getOwner().getName();
        var projectName = ctx. get(CLIENT).project();
        var host = "%s.%s.svc.cluster.local".formatted(serviceName, projectName);
        return new URILike(Protocol.HTTPS.getValue(), host, getInternalHttpsPort(ctx), "");
    }

    private static PropertyToValue getPropertyToValue(String propertyValue, String prefix, String separator, String subject) {
        var keyToVal = propertyValue.replace(prefix, StringUtils.EMPTY);
        var separatorIdx = keyToVal.indexOf(separator);
        if (separatorIdx == -1) {
            Assertions.fail("Configuration property defining OpenShift '%s' is missing key to value separator '%s'"
                    .formatted(subject, separatorIdx));
        }
        var key = keyToVal.substring(0, separatorIdx);
        var value = keyToVal.substring(separatorIdx + 1);
        return new PropertyToValue(key, value);
    }

    private static String createRandomPropertyKeyWithPrefix(String x) {
        var generator = RandomGenerator.getDefault();
        return x + generator.nextInt() + "-" + generator.nextInt();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy