diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c419cc8..e208f83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - preset: [ "okd" ] + preset: [ "openshift", "microshift" ] fail-fast: false steps: - uses: actions/checkout@v4 @@ -74,22 +74,31 @@ jobs: df -h - name: Download crc run: | - wget https://developers.redhat.com/content-gateway/file/pub/openshift-v4/clients/crc/2.40.0/crc-linux-amd64.tar.xz + wget https://developers.redhat.com/content-gateway/file/pub/openshift-v4/clients/crc/2.44.0/crc-linux-amd64.tar.xz mkdir -p bin/ && tar -xJf crc-linux-amd64.tar.xz --strip-components=1 -C bin/ sudo mv ./bin/crc /usr/local/bin/crc && rm -r bin/ - name: Set the crc config run: | - crc config set consent-telemetry no - crc config set network-mode user + echo eyJhdXRocyI6eyJjbG91ZC5vcGVuc2hpZnQuY29tIjp7ImF1dGgiOiJiM0JsYm5Ob2FXWjBMWEpsYkdWaGMyVXRaR1YySzI5amJWOWhZMk5sYzNOZk16RTFaRE16TWpJM09HVXpOR000WTJKbFkyVmxOMlU0TVRoa1pEazNNRGc2VERKSldUVlVUVlZQUTA5VlRraFdTRTFRUjBaRFdEaFBTRUpVTVVaU1RrZEtOMU5EUVZFMlFrOUlPRWRHVERjMVVFeE9UVTB5VFRsUldFZzFSbGMyT1E9PSIsImVtYWlsIjoidHJ1c3QuZ2l0LmJvdEBnbWFpbC5jb20ifSwicXVheS5pbyI6eyJhdXRoIjoiYjNCbGJuTm9hV1owTFhKbGJHVmhjMlV0WkdWMksyOWpiVjloWTJObGMzTmZNekUxWkRNek1qSTNPR1V6TkdNNFkySmxZMlZsTjJVNE1UaGtaRGszTURnNlRESkpXVFZVVFZWUFEwOVZUa2hXU0UxUVIwWkRXRGhQU0VKVU1VWlNUa2RLTjFORFFWRTJRazlJT0VkR1REYzFVRXhPVFUweVRUbFJXRWcxUmxjMk9RPT0iLCJlbWFpbCI6InRydXN0LmdpdC5ib3RAZ21haWwuY29tIn0sInJlZ2lzdHJ5LmNvbm5lY3QucmVkaGF0LmNvbSI6eyJhdXRoIjoiZkhWb1l5MXdiMjlzTFRSak9HTTVOREV5TFRJeFltRXROREUxWmkwNU5UQmxMVEk1TXpWak9HRXhPREk1TmpwbGVVcG9Za2RqYVU5cFNsTlZlbFY0VFdsS09TNWxlVXA2WkZkSmFVOXBTbXhPYWxGNldsUlZNVTFIUlRKT1YwVXdUVEpKTlU5VWFHcFpiVlpzV2tSb2JFMUhSbXhOYW1oc1drTktPUzVuVVRWV05EZHNUalo1U0RCNFFWSnlSRkJPTVhKbFUwNHhTblJaY1ZwdWNqaHJaalZHYkhJd1RWZzNURTFuUTNWSVRqbENRemxDZUc5UFkzQmxhRmgwWTJ0WmFEZE1TMDFKTmpsb1UyVk1jbmRQTFRGT2MwWldhbWxtVUU5QlptRkxUSEl3ZURGeFN5MXZVa0pwWlRKRk0zRlRhRE5YWVVjNGFVOWpkVWR1U0haTlEzWm1NQzExZUZoMmRWRmxiM0o2WDFNM1dHWmFZbGRITW0xWFZFeHNia1JqVlVwb1ptUjRTa1Z3YUdaMllubzFWMEV3V1dJelpGSjFObk5WY1dZNFpFdExUVVkwVlZBNVlUQnVSVk5uUm01cWFtSm1lWEF4VmpkTWFXUkdXR2wwT0hkTlpVeFdkMVJCYkdOSVkwMURRMUpwVW05bU5tUndOMjVyUldnMWNtdENWWGR5Tms1SlVVMXpWWE4xYTAxMlpFVktWVU51TkVKcExVaGtNR2hGUjJkRVp6UnlkamxIWldWNFowMTBhbFJaT0dvelVGTlpRV3hUVFVsVFdteERXVWg0WDBrMWVuRlpPWEV4ZW10aWRtOHpVM0pJY1dWeGRXNXNha3BwUkRCVVdEbGxhVmxyUTJzeldWOXhTbVJOVDBkM1NHVm1OMmx3YlhjMVdsbG5OeTB4WWxVeWFUTXpVMkp1UWtJdFpGQjBValYwYTFJeVEyVlJWVEZTTW1aVVkxQk1lbUZqWWtkcWRrUjJUMmx2ZVhCbmRqVm9abGd4Y1RWelFqTjBWVE5tYnpaMVV6bERlV3BVYVdSd1owTk1NVXBwUkU1T1FraFhRVU54WkVvM09GaG9VM0ZyVDBWRGJFbEtNRlI1V2xock5uVTBSREJ4YzFGVmEzbFFkMHQwWlU5aGRGbGhMVkpITVRKZlIwMUNNSEZIYWtWSGRIbDZaVEpIYzNSd2RsOTZUMlZOYTJSMFEzbEhWMmQ0ZG1GZlJWTlBNVkpJWkVWR1IwWTNhVGt0YmtVemQwSlJYMjE1ZVhaeU1IVlNWVlJUVFZKeE1YY3paRGxoU1V0eldYTnhaRWR1ZWxGMWNYUktWVkJhVGkxRVRFTnhRME53UWtSclpuRkJWbDh3UVhWUVZreGhOa1pWYW1KYVFUTnJURGsyVFZOdkxWaHlVMXAwTVRaNU5GZDNNMlp0YmkxMFVsOVdRUT09IiwiZW1haWwiOiJ0cnVzdC5naXQuYm90QGdtYWlsLmNvbSJ9LCJyZWdpc3RyeS5yZWRoYXQuaW8iOnsiYXV0aCI6ImZIVm9ZeTF3YjI5c0xUUmpPR001TkRFeUxUSXhZbUV0TkRFMVppMDVOVEJsTFRJNU16VmpPR0V4T0RJNU5qcGxlVXBvWWtkamFVOXBTbE5WZWxWNFRXbEtPUzVsZVVwNlpGZEphVTlwU214T2FsRjZXbFJWTVUxSFJUSk9WMFV3VFRKSk5VOVVhR3BaYlZac1drUm9iRTFIUm14TmFtaHNXa05LT1M1blVUVldORGRzVGpaNVNEQjRRVkp5UkZCT01YSmxVMDR4U25SWmNWcHVjamhyWmpWR2JISXdUVmczVEUxblEzVklUamxDUXpsQ2VHOVBZM0JsYUZoMFkydFphRGRNUzAxSk5qbG9VMlZNY25kUExURk9jMFpXYW1sbVVFOUJabUZMVEhJd2VERnhTeTF2VWtKcFpUSkZNM0ZUYUROWFlVYzRhVTlqZFVkdVNIWk5RM1ptTUMxMWVGaDJkVkZsYjNKNlgxTTNXR1phWWxkSE1tMVhWRXhzYmtSalZVcG9abVI0U2tWd2FHWjJZbm8xVjBFd1dXSXpaRkoxTm5OVmNXWTRaRXRMVFVZMFZWQTVZVEJ1UlZOblJtNXFhbUptZVhBeFZqZE1hV1JHV0dsME9IZE5aVXhXZDFSQmJHTklZMDFEUTFKcFVtOW1ObVJ3TjI1clJXZzFjbXRDVlhkeU5rNUpVVTF6VlhOMWEwMTJaRVZLVlVOdU5FSnBMVWhrTUdoRlIyZEVaelJ5ZGpsSFpXVjRaMDEwYWxSWk9Hb3pVRk5aUVd4VFRVbFRXbXhEV1VoNFgwazFlbkZaT1hFeGVtdGlkbTh6VTNKSWNXVnhkVzVzYWtwcFJEQlVXRGxsYVZsclEyc3pXVjl4U21STlQwZDNTR1ZtTjJsd2JYYzFXbGxuTnkweFlsVXlhVE16VTJKdVFrSXRaRkIwVWpWMGExSXlRMlZSVlRGU01tWlVZMUJNZW1GallrZHFka1IyVDJsdmVYQm5kalZvWmxneGNUVnpRak4wVlRObWJ6WjFVemxEZVdwVWFXUndaME5NTVVwcFJFNU9Ra2hYUVVOeFpFbzNPRmhvVTNGclQwVkRiRWxLTUZSNVdsaHJOblUwUkRCeGMxRlZhM2xRZDB0MFpVOWhkRmxoTFZKSE1USmZSMDFDTUhGSGFrVkhkSGw2WlRKSGMzUndkbDk2VDJWTmEyUjBRM2xIVjJkNGRtRmZSVk5QTVZKSVpFVkdSMFkzYVRrdGJrVXpkMEpSWDIxNWVYWnlNSFZTVlZSVFRWSnhNWGN6WkRsaFNVdHpXWE54WkVkdWVsRjFjWFJLVlZCYVRpMUVURU54UTBOd1FrUnJabkZCVmw4d1FYVlFWa3hoTmtaVmFtSmFRVE5yVERrMlRWTnZMVmh5VTFwME1UWjVORmQzTTJadGJpMTBVbDlXUVE9PSIsImVtYWlsIjoidHJ1c3QuZ2l0LmJvdEBnbWFpbC5jb20ifX19 | base64 --decode > pull-secret.txt crc config set preset ${{ matrix.preset }} - - name: Setup the crc - run: sudo -su $USER crc setup - - name: Start the crc + crc config set pull-secret-file pull-secret.txt + crc config set network-mode user + crc config set consent-telemetry no + - name: Setup and Start the crc run: | + sudo -su $USER crc setup sudo -su $USER crc start + sleep 60 + - name: Copy OpenShift client + run: sudo cp /home/$USER/.crc/bin/oc/oc /usr/bin/ + - name: Copy the kubeconfig file to required location + run: | + mkdir -p /home/$USER/.kube + cp /home/$USER/.crc/machines/crc/kubeconfig /home/$USER/.kube/config + oc get pods -A - name: Test run: | - export HOST_KUBERNETES_CONFIG_FILE=${HOME}/.kube/config + export HOST_KUBERNETES_CONFIG_FILE=/home/$USER/.kube/config echo "Using ${HOST_KUBERNETES_CONFIG_FILE} as host k8s" mvn verify diff --git a/src/main/java/org/trustify/operator/Constants.java b/src/main/java/org/trustify/operator/Constants.java index bd72746..9ffd32b 100644 --- a/src/main/java/org/trustify/operator/Constants.java +++ b/src/main/java/org/trustify/operator/Constants.java @@ -53,8 +53,6 @@ public class Constants { public static final String DB_NAME = "trustify"; public static final Integer DB_PORT= 5432; - public static final String DEFAULT_PVC_SIZE = "10G"; - public static final String CERTIFICATES_FOLDER = "/mnt/certificates"; public static final String WORKSPACES_FOLDER = "/mnt/workspace"; } diff --git a/src/main/java/org/trustify/operator/TrustifyConfig.java b/src/main/java/org/trustify/operator/TrustifyConfig.java new file mode 100644 index 0000000..4022460 --- /dev/null +++ b/src/main/java/org/trustify/operator/TrustifyConfig.java @@ -0,0 +1,11 @@ +package org.trustify.operator; + +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithName; + +@ConfigMapping(prefix = "trustify") +public interface TrustifyConfig { + + @WithName("default-pvc-size") + String defaultPvcSize(); +} diff --git a/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBActivationCondition.java b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBActivationCondition.java index 18fe165..033540d 100644 --- a/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBActivationCondition.java +++ b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBActivationCondition.java @@ -1,16 +1,12 @@ package org.trustify.operator.cdrs.v2alpha1.db; import org.trustify.operator.cdrs.v2alpha1.Trustify; -import org.trustify.operator.cdrs.v2alpha1.TrustifySpec; - -import java.util.Optional; +import org.trustify.operator.cdrs.v2alpha1.server.utils.ServerUtils; public abstract class DBActivationCondition { protected boolean isMet(Trustify cr) { - return !Optional.ofNullable(cr.getSpec().databaseSpec()) - .map(TrustifySpec.DatabaseSpec::externalDatabase) - .orElse(false); + return ServerUtils.isServerDBRequired(cr); } } diff --git a/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBDeployment.java b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBDeployment.java index 9742a83..76333e1 100644 --- a/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBDeployment.java +++ b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBDeployment.java @@ -14,6 +14,7 @@ import org.trustify.operator.Constants; import org.trustify.operator.cdrs.v2alpha1.Trustify; import org.trustify.operator.cdrs.v2alpha1.TrustifySpec; +import org.trustify.operator.cdrs.v2alpha1.db.utils.DBUtils; import org.trustify.operator.utils.CRDUtils; import java.util.Arrays; @@ -56,17 +57,8 @@ public Result match(Deployment actual, Trustify cr, Context dependentResource, Trustify primary, Context context) { - return context.getSecondaryResource(Deployment.class, new DBDeploymentDiscriminator()) - .map(deployment -> { - final var status = deployment.getStatus(); - if (status != null) { - final var readyReplicas = status.getReadyReplicas(); - return readyReplicas != null && readyReplicas >= 1; - } - return false; - }) - .orElse(false); + public boolean isMet(DependentResource dependentResource, Trustify cr, Context context) { + return DBUtils.isDeploymentReady(dependentResource, cr, context); } @SuppressWarnings("unchecked") diff --git a/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBPersistentVolumeClaim.java b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBPersistentVolumeClaim.java index 934aa2d..0d982ac 100644 --- a/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBPersistentVolumeClaim.java +++ b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBPersistentVolumeClaim.java @@ -7,7 +7,9 @@ import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; import org.trustify.operator.Constants; +import org.trustify.operator.TrustifyConfig; import org.trustify.operator.cdrs.v2alpha1.Trustify; import org.trustify.operator.cdrs.v2alpha1.TrustifySpec; import org.trustify.operator.utils.CRDUtils; @@ -21,6 +23,9 @@ public class DBPersistentVolumeClaim extends CRUDKubernetesDependentResource implements Creator { + public static final String LABEL_SELECTOR = "app.kubernetes.io/managed-by=trustify-operator,component=db"; + public DBSecret() { super(Secret.class); } @@ -42,6 +46,7 @@ private Secret newSecret(Trustify cr, Context context) { .withName(getSecretName(cr)) .withNamespace(cr.getMetadata().getNamespace()) .withLabels(labels) + .addToLabels("component", "db") .withOwnerReferences(CRDUtils.getOwnerReference(cr)) .endMetadata() .addToStringData(Constants.DB_SECRET_USERNAME, generateRandomString(10)) diff --git a/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBSecretDiscriminator.java b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBSecretDiscriminator.java new file mode 100644 index 0000000..5bfd673 --- /dev/null +++ b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/DBSecretDiscriminator.java @@ -0,0 +1,21 @@ +package org.trustify.operator.cdrs.v2alpha1.db; + +import io.fabric8.kubernetes.api.model.Secret; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; +import org.trustify.operator.cdrs.v2alpha1.Trustify; +import org.trustify.operator.controllers.TrustifyReconciler; + +import java.util.Optional; + +public class DBSecretDiscriminator implements ResourceDiscriminator { + @Override + public Optional distinguish(Class resource, Trustify cr, Context context) { + String secret = DBSecret.getSecretName(cr); + ResourceID resourceID = new ResourceID(secret, cr.getMetadata().getNamespace()); + var informerEventSource = (InformerEventSource) context.eventSourceRetriever().getResourceEventSourceFor(Secret.class, TrustifyReconciler.SECRET_EVENT_SOURCE); + return informerEventSource.get(resourceID); + } +} diff --git a/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/utils/DBUtils.java b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/utils/DBUtils.java new file mode 100644 index 0000000..78b29d8 --- /dev/null +++ b/src/main/java/org/trustify/operator/cdrs/v2alpha1/db/utils/DBUtils.java @@ -0,0 +1,24 @@ +package org.trustify.operator.cdrs.v2alpha1.db.utils; + +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import org.trustify.operator.cdrs.v2alpha1.Trustify; +import org.trustify.operator.cdrs.v2alpha1.db.DBDeploymentDiscriminator; + +public class DBUtils { + + public static boolean isDeploymentReady(DependentResource dependentResource, Trustify primary, Context context) { + return context.getSecondaryResource(Deployment.class, new DBDeploymentDiscriminator()) + .map(deployment -> { + final var status = deployment.getStatus(); + if (status != null) { + final var readyReplicas = status.getReadyReplicas(); + return readyReplicas != null && readyReplicas >= 1; + } + return false; + }) + .orElse(false); + } + +} diff --git a/src/main/java/org/trustify/operator/cdrs/v2alpha1/server/ServerStoragePersistentVolumeClaim.java b/src/main/java/org/trustify/operator/cdrs/v2alpha1/server/ServerStoragePersistentVolumeClaim.java index 5cced6f..f1d0a7c 100644 --- a/src/main/java/org/trustify/operator/cdrs/v2alpha1/server/ServerStoragePersistentVolumeClaim.java +++ b/src/main/java/org/trustify/operator/cdrs/v2alpha1/server/ServerStoragePersistentVolumeClaim.java @@ -6,7 +6,9 @@ import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; import org.trustify.operator.Constants; +import org.trustify.operator.TrustifyConfig; import org.trustify.operator.cdrs.v2alpha1.Trustify; import org.trustify.operator.cdrs.v2alpha1.TrustifySpec; import org.trustify.operator.utils.CRDUtils; @@ -21,6 +23,9 @@ public class ServerStoragePersistentVolumeClaim extends CRUDKubernetesDependentR public static final String LABEL_SELECTOR = "app.kubernetes.io/managed-by=trustify-operator,component=server"; + @Inject + TrustifyConfig trustifyConfig; + public ServerStoragePersistentVolumeClaim() { super(PersistentVolumeClaim.class); } @@ -38,7 +43,7 @@ private PersistentVolumeClaim newPersistentVolumeClaim(Trustify cr, Context Optional.ofNullable(storageSpec.filesystemStorageSpec())) .map(TrustifySpec.FilesystemStorageSpec::pvcSize) - .orElse(Constants.DEFAULT_PVC_SIZE); + .orElse(trustifyConfig.defaultPvcSize()); return new PersistentVolumeClaimBuilder() .withNewMetadata() diff --git a/src/main/java/org/trustify/operator/cdrs/v2alpha1/server/utils/ServerUtils.java b/src/main/java/org/trustify/operator/cdrs/v2alpha1/server/utils/ServerUtils.java new file mode 100644 index 0000000..9b35370 --- /dev/null +++ b/src/main/java/org/trustify/operator/cdrs/v2alpha1/server/utils/ServerUtils.java @@ -0,0 +1,15 @@ +package org.trustify.operator.cdrs.v2alpha1.server.utils; + +import org.trustify.operator.cdrs.v2alpha1.Trustify; +import org.trustify.operator.cdrs.v2alpha1.TrustifySpec; + +import java.util.Optional; + +public class ServerUtils { + + public static boolean isServerDBRequired(Trustify cr) { + return !Optional.ofNullable(cr.getSpec().databaseSpec()) + .map(TrustifySpec.DatabaseSpec::externalDatabase) + .orElse(false); + } +} diff --git a/src/main/java/org/trustify/operator/cdrs/v2alpha1/ui/UIDeployment.java b/src/main/java/org/trustify/operator/cdrs/v2alpha1/ui/UIDeployment.java index 78b44df..68b8559 100644 --- a/src/main/java/org/trustify/operator/cdrs/v2alpha1/ui/UIDeployment.java +++ b/src/main/java/org/trustify/operator/cdrs/v2alpha1/ui/UIDeployment.java @@ -207,6 +207,10 @@ private List getEnvVars(Trustify cr) { new EnvVarBuilder() .withName("UI_INGRESS_PROXY_BODY_SIZE") .withValue("50m") + .build(), + new EnvVarBuilder() + .withName("NODE_EXTRA_CA_CERTS") + .withValue("/opt/app-root/src/ca.crt") .build() ); } diff --git a/src/main/java/org/trustify/operator/controllers/TrustifyReconciler.java b/src/main/java/org/trustify/operator/controllers/TrustifyReconciler.java index 039ac50..1dbd344 100644 --- a/src/main/java/org/trustify/operator/controllers/TrustifyReconciler.java +++ b/src/main/java/org/trustify/operator/controllers/TrustifyReconciler.java @@ -1,6 +1,8 @@ package org.trustify.operator.controllers; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; +import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; @@ -88,7 +90,9 @@ public class TrustifyReconciler implements Reconciler, ContextInitiali private static final Logger logger = Logger.getLogger(TrustifyReconciler.class); + public static final String CONFIG_MAP_EVENT_SOURCE = "configMapSource"; public static final String PVC_EVENT_SOURCE = "pcvSource"; + public static final String SECRET_EVENT_SOURCE = "secretSource"; public static final String DEPLOYMENT_EVENT_SOURCE = "deploymentSource"; public static final String SERVICE_EVENT_SOURCE = "serviceSource"; @@ -110,7 +114,7 @@ public UpdateControl reconcile(Trustify cr, Context context) { .map(wrs -> { if (wrs.allDependentResourcesReady()) { if (cr.getStatus().isAvailable()) { - logger.infof("Trustify {} is ready to be used", cr.getMetadata().getName()); + logger.infof("Trustify %s is ready to be used", cr.getMetadata().getName()); } TrustifyStatusCondition status = new TrustifyStatusCondition(); @@ -136,16 +140,22 @@ public UpdateControl reconcile(Trustify cr, Context context) { @Override public Map prepareEventSources(EventSourceContext context) { + var configMapInformerConfiguration = InformerConfiguration.from(ConfigMap.class, context).build(); var pcvInformerConfiguration = InformerConfiguration.from(PersistentVolumeClaim.class, context).build(); + var secretInformerConfiguration = InformerConfiguration.from(Secret.class, context).build(); var deploymentInformerConfiguration = InformerConfiguration.from(Deployment.class, context).build(); var serviceInformerConfiguration = InformerConfiguration.from(Service.class, context).build(); + var configMapInformerConfigurationInformerEventSource = new InformerEventSource<>(configMapInformerConfiguration, context); var pcvInformerEventSource = new InformerEventSource<>(pcvInformerConfiguration, context); + var secretInformerEventSource = new InformerEventSource<>(secretInformerConfiguration, context); var deploymentInformerEventSource = new InformerEventSource<>(deploymentInformerConfiguration, context); var serviceInformerEventSource = new InformerEventSource<>(serviceInformerConfiguration, context); return Map.of( + CONFIG_MAP_EVENT_SOURCE, configMapInformerConfigurationInformerEventSource, PVC_EVENT_SOURCE, pcvInformerEventSource, + SECRET_EVENT_SOURCE, secretInformerEventSource, DEPLOYMENT_EVENT_SOURCE, deploymentInformerEventSource, SERVICE_EVENT_SOURCE, serviceInformerEventSource ); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 258c305..195f92f 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1,3 +1,8 @@ +trustify: + default-pvc-size: 10G +"%test": + trustify: + default-pvc-size: 1G # Operator config related: image: diff --git a/src/test/java/org/trustify/operator/controllers/DatabaseSpecTest.java b/src/test/java/org/trustify/operator/controllers/DatabaseSpecTest.java new file mode 100644 index 0000000..fc12c8e --- /dev/null +++ b/src/test/java/org/trustify/operator/controllers/DatabaseSpecTest.java @@ -0,0 +1,141 @@ +package org.trustify.operator.controllers; + +import io.fabric8.kubernetes.api.model.SecretKeySelector; +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; +import org.awaitility.Awaitility; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.trustify.operator.cdrs.v2alpha1.Trustify; +import org.trustify.operator.cdrs.v2alpha1.TrustifySpec; +import org.trustify.operator.cdrs.v2alpha1.db.DBDeployment; +import org.trustify.operator.controllers.setup.K3sResource; + +import java.io.InputStream; +import java.util.concurrent.TimeUnit; + +@QuarkusTestResource(K3sResource.class) +@QuarkusTest +public class DatabaseSpecTest extends ReconcilerBaseTest { + + @Test + public void externalDatabase() throws InterruptedException { + // Create external database + InputStream postgresqlYaml = DatabaseSpecTest.class.getClassLoader().getResourceAsStream("helpers/example-postgres.yaml"); + var resources = client.load(postgresqlYaml).inNamespace(getNamespaceName()); + createResources(resources); + + Awaitility.await() + .ignoreException(NullPointerException.class) + .atMost(2, TimeUnit.MINUTES) + .untilAsserted(() -> { + final var statefulSet = client.apps() + .statefulSets() + .inNamespace(getNamespaceName()) + .withName("postgresql-db") + .get(); + Assertions.assertEquals(1, statefulSet.getStatus().getReadyReplicas(), "External DB number of replicas is wrong"); + + final var dbService = client.services() + .inNamespace(getNamespaceName()) + .withName("postgresql-db") + .get(); + final var dbPort = dbService.getSpec() + .getPorts() + .getFirst() + .getPort(); + MatcherAssert.assertThat("DB service port not valid", dbPort, Matchers.is(5432)); + }); + + // Create + final Trustify trustify = generateTrustify("external-database"); + trustify.setSpec(new TrustifySpec( + null, + null, + null, + null, + null, + new TrustifySpec.DatabaseSpec( + true, + null, + null, + new SecretKeySelector("username", "postgresql-db", false), + new SecretKeySelector("password", "postgresql-db", false), + "postgresql-db." + getNamespaceName() + ".svc", + "5432", + "database" + ), + null, + null, + null, + null, + null, + null + )); + + createTrustify(trustify); + + // Verify resources + Awaitility.await() + .ignoreException(NullPointerException.class) + .atMost(2, TimeUnit.MINUTES) + .untilAsserted(() -> { + // Database should not be created + final var dbDeployment = client.apps() + .deployments() + .inNamespace(getNamespaceName()) + .withName(DBDeployment.getDeploymentName(trustify)) + .get(); + Assertions.assertNull(dbDeployment, "DB should not be created as an external one is used"); + + verifyServer(trustify); + verifyUI(trustify); + verifyIngress(trustify); + }); + } + + @Test + public void providedDatabase() throws InterruptedException { + // Create + final Trustify trustify = generateTrustify("provided-database"); + trustify.setSpec(new TrustifySpec( + null, + null, + null, + null, + null, + new TrustifySpec.DatabaseSpec( + false, + null, + null, + null, + null, + null, + null, + null + ), + null, + null, + null, + null, + null, + null + )); + + createTrustify(trustify); + + // Verify resources + Awaitility.await() + .ignoreException(NullPointerException.class) + .atMost(2, TimeUnit.MINUTES) + .untilAsserted(() -> { + verifyDatabase(trustify); + verifyServer(trustify); + verifyUI(trustify); + verifyIngress(trustify); + }); + } + +} \ No newline at end of file diff --git a/src/test/java/org/trustify/operator/controllers/DefaultSpecTest.java b/src/test/java/org/trustify/operator/controllers/DefaultSpecTest.java new file mode 100644 index 0000000..fe33c0b --- /dev/null +++ b/src/test/java/org/trustify/operator/controllers/DefaultSpecTest.java @@ -0,0 +1,33 @@ +package org.trustify.operator.controllers; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; +import org.trustify.operator.cdrs.v2alpha1.Trustify; +import org.trustify.operator.controllers.setup.K3sResource; + +import java.util.concurrent.TimeUnit; + +@QuarkusTestResource(K3sResource.class) +@QuarkusTest +public class DefaultSpecTest extends ReconcilerBaseTest { + + @Test + public void defaultSpec() throws InterruptedException { + final Trustify trustify = generateTrustify("default-spec"); + createTrustify(trustify); + + // Verify resources + Awaitility.await() + .ignoreException(NullPointerException.class) + .atMost(2, TimeUnit.MINUTES) + .untilAsserted(() -> { + verifyDatabase(trustify); + verifyServer(trustify); + verifyUI(trustify); + verifyIngress(trustify); + }); + } + +} \ No newline at end of file diff --git a/src/test/java/org/trustify/operator/controllers/HostnameSpecTest.java b/src/test/java/org/trustify/operator/controllers/HostnameSpecTest.java new file mode 100644 index 0000000..a13ddf7 --- /dev/null +++ b/src/test/java/org/trustify/operator/controllers/HostnameSpecTest.java @@ -0,0 +1,71 @@ +package org.trustify.operator.controllers; + +import io.fabric8.kubernetes.api.model.SecretKeySelector; +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; +import org.awaitility.Awaitility; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.trustify.operator.cdrs.v2alpha1.Trustify; +import org.trustify.operator.cdrs.v2alpha1.TrustifySpec; +import org.trustify.operator.cdrs.v2alpha1.db.DBDeployment; +import org.trustify.operator.cdrs.v2alpha1.ui.UIIngress; +import org.trustify.operator.cdrs.v2alpha1.ui.UIService; +import org.trustify.operator.controllers.setup.K3sResource; + +import java.io.InputStream; +import java.util.concurrent.TimeUnit; + +@QuarkusTestResource(K3sResource.class) +@QuarkusTest +public class HostnameSpecTest extends ReconcilerBaseTest { + + @Test + public void customHostname() throws InterruptedException { + String host = "app1.example.com"; + + // Create + final Trustify trustify = generateTrustify("custom-hostname"); + trustify.setSpec(new TrustifySpec( + null, + null, + null, + null, + null, + null, + new TrustifySpec.HostnameSpec( + host + ), + null, + null, + null, + null, + null + )); + + createTrustify(trustify); + + // Verify resources + Awaitility.await() + .ignoreException(NullPointerException.class) + .atMost(2, TimeUnit.MINUTES) + .untilAsserted(() -> { + verifyDatabase(trustify); + verifyServer(trustify); + verifyUI(trustify); + verifyIngress(trustify); + + // Ingress + final var ingress = client.network().v1().ingresses() + .inNamespace(client.getNamespace()) + .withName(UIIngress.getIngressName(trustify)) + .get(); + + final var rules = ingress.getSpec().getRules(); + Assertions.assertEquals(host, rules.getFirst().getHost()); + }); + } + +} \ No newline at end of file diff --git a/src/test/java/org/trustify/operator/controllers/ReconcilerBaseTest.java b/src/test/java/org/trustify/operator/controllers/ReconcilerBaseTest.java new file mode 100644 index 0000000..e9de8ea --- /dev/null +++ b/src/test/java/org/trustify/operator/controllers/ReconcilerBaseTest.java @@ -0,0 +1,276 @@ +package org.trustify.operator.controllers; + +import io.fabric8.kubernetes.api.model.*; +import io.fabric8.kubernetes.api.model.batch.v1.Job; +import io.fabric8.kubernetes.api.model.batch.v1.JobBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.ListVisitFromServerGetDeleteRecreateWaitApplicable; +import io.javaoperatorsdk.operator.Operator; +import jakarta.inject.Inject; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.trustify.operator.cdrs.v2alpha1.Trustify; +import org.trustify.operator.cdrs.v2alpha1.db.DBDeployment; +import org.trustify.operator.cdrs.v2alpha1.db.DBService; +import org.trustify.operator.cdrs.v2alpha1.server.ServerDeployment; +import org.trustify.operator.cdrs.v2alpha1.server.ServerService; +import org.trustify.operator.cdrs.v2alpha1.ui.UIDeployment; +import org.trustify.operator.cdrs.v2alpha1.ui.UIIngress; +import org.trustify.operator.cdrs.v2alpha1.ui.UIService; + +import java.util.List; +import java.util.Objects; + +public abstract class ReconcilerBaseTest { + + @ConfigProperty(name = "related.image.db") + String dbImage; + + @ConfigProperty(name = "related.image.ui") + String uiImage; + + @ConfigProperty(name = "related.image.server") + String serverImage; + + @Inject + KubernetesClient client; + + @Inject + Operator operator; + + protected Namespace namespace = null; + protected Job imagePullerJob = null; + + private Trustify trustify; + private ListVisitFromServerGetDeleteRecreateWaitApplicable resources; + + @BeforeEach + public void beforeEach() { + // Create namespace + namespace = new NamespaceBuilder() + .withNewMetadata() + .withName(client.getNamespace()) + .endMetadata() + .build(); + if (client.resource(namespace).get() == null) { + client.resource(namespace).create(); + } + + // Create a pod to pull images. This is just to make things faster during test time + imagePullerJob = new JobBuilder() + .withNewMetadata() + .withName("pull-images") + .endMetadata() + .withNewSpec() + .withBackoffLimit(1) + .withNewTemplate() + .withNewSpec() + .withRestartPolicy("Never") + .withContainers( + new ContainerBuilder() + .withName("database") + .withImage(dbImage) + .withCommand("echo") + .withArgs("Database image pulled") + .build(), + new ContainerBuilder() + .withName("backend") + .withImage(serverImage) + .withCommand("echo") + .withArgs("Backend image pulled") + .build(), + new ContainerBuilder() + .withName("ui") + .withImage(uiImage) + .withCommand("echo") + .withArgs("UI image pulled") + .build() + ) + .endSpec() + .endTemplate() + .endSpec() + .build(); + + if (client.resource(imagePullerJob).inNamespace(getNamespaceName()).get() == null) { + client.batch().v1().jobs().inNamespace(getNamespaceName()).resource(imagePullerJob).create(); + } + + // Start the operator + operator.start(); + } + + @AfterEach + public void afterEach() throws InterruptedException { + if (resources != null || trustify != null) { + if (resources != null) { + resources.delete(); + } + if (trustify != null) { + client.resource(trustify) + .inNamespace(getNamespaceName()) + .delete(); + } + Thread.sleep(2_000); + } + } + + protected String getNamespaceName() { + return namespace.getMetadata().getName(); + } + + protected Trustify generateTrustify(String name) { + Trustify trustify = new Trustify(); + trustify.setMetadata(new ObjectMetaBuilder() + .withName(name) + .withNamespace(getNamespaceName()) + .build() + ); + return trustify; + } + + protected void createTrustify(Trustify trustify) throws InterruptedException { + if (client.resource(trustify).inNamespace(getNamespaceName()) != null) { + client.resource(trustify) + .inNamespace(getNamespaceName()) + .delete(); + Thread.sleep(2_000); + } + this.trustify = client.resource(trustify) + .inNamespace(getNamespaceName()) + .create(); + } + + protected void createResources(ListVisitFromServerGetDeleteRecreateWaitApplicable resources) throws InterruptedException { + if (resources.resources().anyMatch(Objects::nonNull)) { + resources.delete(); + Thread.sleep(2_000); + } + resources.create(); + + this.resources = resources; + } + + protected void verifyDatabase(Trustify cr) { + // Database + final var dbDeployment = client.apps() + .deployments() + .inNamespace(cr.getMetadata().getNamespace()) + .withName(DBDeployment.getDeploymentName(cr)) + .get(); + final var dbContainer = dbDeployment.getSpec() + .getTemplate() + .getSpec() + .getContainers() + .stream() + .findFirst(); + MatcherAssert.assertThat("DB container not found", dbContainer.isPresent(), Matchers.is(true)); + MatcherAssert.assertThat("DB container image not valid", dbContainer.get().getImage(), Matchers.is(dbImage)); + + Assertions.assertEquals(1, dbDeployment.getStatus().getReadyReplicas(), "Expected DB deployment number of replicas doesn't match"); + + // Database service + final var dbService = client.services() + .inNamespace(cr.getMetadata().getNamespace()) + .withName(DBService.getServiceName(cr)) + .get(); + final var dbPort = dbService.getSpec() + .getPorts() + .get(0) + .getPort(); + MatcherAssert.assertThat("DB service port not valid", dbPort, Matchers.is(5432)); + } + + protected void verifyServer(Trustify cr) { + // Server Deployment + final var serverDeployment = client.apps() + .deployments() + .inNamespace(cr.getMetadata().getNamespace()) + .withName(ServerDeployment.getDeploymentName(cr)) + .get(); + final var serverContainer = serverDeployment.getSpec() + .getTemplate() + .getSpec() + .getContainers() + .stream() + .findFirst(); + MatcherAssert.assertThat("Server container not found", serverContainer.isPresent(), Matchers.is(true)); + MatcherAssert.assertThat("Server container image not valid", serverContainer.get().getImage(), Matchers.is(serverImage)); + List serverContainerPorts = serverContainer.get().getPorts().stream() + .map(ContainerPort::getContainerPort) + .toList(); + Assertions.assertTrue(serverContainerPorts.contains(8080), "Server container port 8080 not found"); + + Assertions.assertEquals(1, serverDeployment.getStatus().getAvailableReplicas(), "Expected Server deployment number of replicas doesn't match"); + + // Server service + final var serverService = client.services() + .inNamespace(cr.getMetadata().getNamespace()) + .withName(ServerService.getServiceName(cr)) + .get(); + final var serverServicePorts = serverService.getSpec() + .getPorts() + .stream() + .map(ServicePort::getPort) + .toList(); + Assertions.assertTrue(serverServicePorts.contains(8080), "Server service port not valid"); + } + + protected void verifyUI(Trustify cr) { + // UI Deployment + final var uiDeployment = client.apps() + .deployments() + .inNamespace(cr.getMetadata().getNamespace()) + .withName(UIDeployment.getDeploymentName(cr)) + .get(); + final var uiContainer = uiDeployment.getSpec() + .getTemplate() + .getSpec() + .getContainers() + .stream() + .findFirst(); + MatcherAssert.assertThat("UI container not found", uiContainer.isPresent(), Matchers.is(true)); + MatcherAssert.assertThat("UI container image not valid", uiContainer.get().getImage(), Matchers.is(uiImage)); + List uiContainerPorts = uiContainer.get().getPorts().stream() + .map(ContainerPort::getContainerPort) + .toList(); + Assertions.assertTrue(uiContainerPorts.contains(8080), "UI container port 8080 not found"); + + Assertions.assertEquals(1, uiDeployment.getStatus().getAvailableReplicas(), "Expected UI deployment number of replicas doesn't match"); + + // Server service + final var uiService = client.services() + .inNamespace(cr.getMetadata().getNamespace()) + .withName(UIService.getServiceName(cr)) + .get(); + final var uiServicePorts = uiService.getSpec() + .getPorts() + .stream() + .map(ServicePort::getPort) + .toList(); + Assertions.assertTrue(uiServicePorts.contains(8080), "UI service port not valid"); + } + + protected void verifyIngress(Trustify cr) { + // Ingress + final var ingress = client.network().v1().ingresses() + .inNamespace(cr.getMetadata().getNamespace()) + .withName(UIIngress.getIngressName(cr)) + .get(); + + final var rules = ingress.getSpec().getRules(); + MatcherAssert.assertThat(rules.size(), Matchers.is(1)); + + final var paths = rules.get(0).getHttp().getPaths(); + MatcherAssert.assertThat(paths.size(), Matchers.is(1)); + + final var path = paths.get(0); + + final var serviceBackend = path.getBackend().getService(); + MatcherAssert.assertThat(serviceBackend.getName(), Matchers.is(UIService.getServiceName(cr))); + MatcherAssert.assertThat(serviceBackend.getPort().getNumber(), Matchers.is(8080)); + } +} \ No newline at end of file diff --git a/src/test/java/org/trustify/operator/controllers/TrustifyReconcilerTest.java b/src/test/java/org/trustify/operator/controllers/TrustifyReconcilerTest.java deleted file mode 100644 index 503a747..0000000 --- a/src/test/java/org/trustify/operator/controllers/TrustifyReconcilerTest.java +++ /dev/null @@ -1,219 +0,0 @@ -package org.trustify.operator.controllers; - -import io.fabric8.kubernetes.api.model.*; -import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.Operator; -import io.quarkus.test.common.QuarkusTestResource; -import io.quarkus.test.junit.QuarkusTest; -import jakarta.inject.Inject; -import org.awaitility.Awaitility; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.*; -import org.trustify.operator.Constants; -import org.trustify.operator.cdrs.v2alpha1.Trustify; -import org.trustify.operator.cdrs.v2alpha1.db.DBDeployment; -import org.trustify.operator.cdrs.v2alpha1.db.DBService; -import org.trustify.operator.cdrs.v2alpha1.server.ServerDeployment; -import org.trustify.operator.cdrs.v2alpha1.ui.UIDeployment; -import org.trustify.operator.cdrs.v2alpha1.ui.UIIngress; -import org.trustify.operator.cdrs.v2alpha1.server.ServerService; -import org.trustify.operator.cdrs.v2alpha1.db.DBDeployment; -import org.trustify.operator.cdrs.v2alpha1.db.DBService; -import org.trustify.operator.cdrs.v2alpha1.ui.UIService; -import org.trustify.operator.controllers.setup.K3sResource; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -@QuarkusTestResource(K3sResource.class) -@QuarkusTest -public class TrustifyReconcilerTest { - - public static final String TEST_APP = "myapp"; - - @ConfigProperty(name = "related.image.db") - String dbImage; - - @ConfigProperty(name = "related.image.ui") - String uiImage; - - @ConfigProperty(name = "related.image.server") - String serverImage; - - @Inject - KubernetesClient client; - - @Inject - Operator operator; - - @BeforeEach - public void startOperator() { - operator.start(); - } - - @AfterEach - public void stopOperator() { - operator.stop(); - } - - @Test - @Order(1) - public void reconcileShouldWork() throws InterruptedException { - // Requirements - client.resource(new NamespaceBuilder() - .withNewMetadata() - .withName(client.getNamespace()) - .endMetadata() - .build() - ) - .create(); - - client.resource(new ServiceAccountBuilder() - .withNewMetadata() - .withName(Constants.TRUSTI_NAME) - .endMetadata() - .build() - ) - .inNamespace(client.getNamespace()) - .create(); - - // - final var app = new Trustify(); - final var metadata = new ObjectMetaBuilder() - .withName(TEST_APP) - .withNamespace(client.getNamespace()) - .build(); - app.setMetadata(metadata); - - // Delete prev instance if exists already - if (client.resource(app).inNamespace(metadata.getNamespace()).get() != null) { - client.resource(app).inNamespace(metadata.getNamespace()).delete(); - Thread.sleep(10_000); - } - - // Instantiate Trusti - client.resource(app).inNamespace(metadata.getNamespace()).serverSideApply(); - - // Verify resources - Awaitility.await() - .ignoreException(NullPointerException.class) - .atMost(2, TimeUnit.MINUTES) - .untilAsserted(() -> { - // Database - final var dbDeployment = client.apps() - .deployments() - .inNamespace(metadata.getNamespace()) - .withName(DBDeployment.getDeploymentName(app)) - .get(); - final var dbContainer = dbDeployment.getSpec() - .getTemplate() - .getSpec() - .getContainers() - .stream() - .findFirst(); - MatcherAssert.assertThat("DB container not found", dbContainer.isPresent(), Matchers.is(true)); - MatcherAssert.assertThat("DB container image not valid", dbContainer.get().getImage(), Matchers.is(dbImage)); - - Assertions.assertEquals(1, dbDeployment.getStatus().getReadyReplicas(), "Expected DB deployment number of replicas doesn't match"); - - // Database service - final var dbService = client.services() - .inNamespace(metadata.getNamespace()) - .withName(DBService.getServiceName(app)) - .get(); - final var dbPort = dbService.getSpec() - .getPorts() - .get(0) - .getPort(); - MatcherAssert.assertThat("DB service port not valid", dbPort, Matchers.is(5432)); - - - // Server Deployment - final var serverDeployment = client.apps() - .deployments() - .inNamespace(metadata.getNamespace()) - .withName(ServerDeployment.getDeploymentName(app)) - .get(); - final var serverContainer = serverDeployment.getSpec() - .getTemplate() - .getSpec() - .getContainers() - .stream() - .findFirst(); - MatcherAssert.assertThat("Server container not found", serverContainer.isPresent(), Matchers.is(true)); - MatcherAssert.assertThat("Server container image not valid", serverContainer.get().getImage(), Matchers.is(serverImage)); - List serverContainerPorts = serverContainer.get().getPorts().stream() - .map(ContainerPort::getContainerPort) - .toList(); - Assertions.assertTrue(serverContainerPorts.contains(8080), "Server container port 8080 not found"); - - Assertions.assertEquals(1, serverDeployment.getStatus().getAvailableReplicas(), "Expected Server deployment number of replicas doesn't match"); - - // Server service - final var serverService = client.services() - .inNamespace(metadata.getNamespace()) - .withName(ServerService.getServiceName(app)) - .get(); - final var serverServicePorts = serverService.getSpec() - .getPorts() - .stream() - .map(ServicePort::getPort) - .toList(); - Assertions.assertTrue(serverServicePorts.contains(8080), "Server service port not valid"); - - // UI Deployment - final var uiDeployment = client.apps() - .deployments() - .inNamespace(metadata.getNamespace()) - .withName(UIDeployment.getDeploymentName(app)) - .get(); - final var uiContainer = uiDeployment.getSpec() - .getTemplate() - .getSpec() - .getContainers() - .stream() - .findFirst(); - MatcherAssert.assertThat("UI container not found", uiContainer.isPresent(), Matchers.is(true)); - MatcherAssert.assertThat("UI container image not valid", uiContainer.get().getImage(), Matchers.is(uiImage)); - List uiContainerPorts = uiContainer.get().getPorts().stream() - .map(ContainerPort::getContainerPort) - .toList(); - Assertions.assertTrue(uiContainerPorts.contains(8080), "UI container port 8080 not found"); - - Assertions.assertEquals(1, uiDeployment.getStatus().getAvailableReplicas(), "Expected UI deployment number of replicas doesn't match"); - - // Server service - final var uiService = client.services() - .inNamespace(metadata.getNamespace()) - .withName(UIService.getServiceName(app)) - .get(); - final var uiServicePorts = uiService.getSpec() - .getPorts() - .stream() - .map(ServicePort::getPort) - .toList(); - Assertions.assertTrue(uiServicePorts.contains(8080), "UI service port not valid"); - - - // Ingress - final var ingress = client.network().v1().ingresses() - .inNamespace(metadata.getNamespace()) - .withName(UIIngress.getIngressName(app)) - .get(); - - final var rules = ingress.getSpec().getRules(); - MatcherAssert.assertThat(rules.size(), Matchers.is(1)); - - final var paths = rules.get(0).getHttp().getPaths(); - MatcherAssert.assertThat(paths.size(), Matchers.is(1)); - - final var path = paths.get(0); - - final var serviceBackend = path.getBackend().getService(); - MatcherAssert.assertThat(serviceBackend.getName(), Matchers.is(UIService.getServiceName(app))); - MatcherAssert.assertThat(serviceBackend.getPort().getNumber(), Matchers.is(8080)); - }); - } -} \ No newline at end of file diff --git a/src/test/resources/helpers/example-postgres.yaml b/src/test/resources/helpers/example-postgres.yaml new file mode 100644 index 0000000..e4c1b93 --- /dev/null +++ b/src/test/resources/helpers/example-postgres.yaml @@ -0,0 +1,61 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: postgresql-db +type: Opaque +stringData: + username: "testuser" + password: "testpassword" +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: postgresql-db +spec: + serviceName: postgresql-db-service + selector: + matchLabels: + app: postgresql-db + replicas: 1 + template: + metadata: + labels: + app: postgresql-db + spec: + containers: + - name: postgresql-db + image: postgres:15 + volumeMounts: + - mountPath: /data + name: cache-volume + env: + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: postgresql-db + key: username + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: postgresql-db + key: password + - name: PGDATA + value: /data/pgdata + - name: POSTGRES_DB + value: database + volumes: + - name: cache-volume + emptyDir: { } +--- +apiVersion: v1 +kind: Service +metadata: + name: postgresql-db +spec: + selector: + app: postgresql-db + type: LoadBalancer + ports: + - port: 5432 + targetPort: 5432 \ No newline at end of file