Commit 38a6752f authored by Vasilis Katopodis's avatar Vasilis Katopodis
Browse files

feat: resolve kubeconfigSecretIds on deployment kubeconfig requests

parent 312557bf
Loading
Loading
Loading
Loading
Loading
+1 −0
Changes for src/main/java/org/etsi/osl/hypo/registry/model/kafka/incoming/KubeConfigRequest.java: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ public class KubeConfigRequest implements KafkaRequestPayload {
    private JsonNode serviceOperationRequest;
    private String kubernetesServiceID;
    private List<String> secretNames;
    private List<String> kubeconfigSecretIds;

    public String toStringAsJson() {
        return JsonObjectWriter.writeValueAsJsonString(this);
+18 −0
Changes for src/main/java/org/etsi/osl/hypo/registry/model/kafka/outgoing/KubeconfigSecret.java: 18 added lines, 0 removed lines.
Original line number Diff line number Diff line
package org.etsi.osl.hypo.registry.model.kafka.outgoing;

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;

/** A kubeconfig resolved from one of the request's {@code kubeconfigSecretIds}. */
@Data
public class KubeconfigSecret {

    @JsonProperty("id")
    @NotNull
    private String id;

    @JsonProperty("kubeConfigAsBase64")
    @NotNull
    private String kubeConfigAsBase64;
}
+4 −0
Changes for src/main/java/org/etsi/osl/hypo/registry/model/registry/KubeConfigMessage.java: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import java.util.List;
import lombok.Data;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.ImagePullSecret;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.KubeconfigSecret;
import org.etsi.osl.hypo.registry.utils.JsonObjectWriter;

@Data
@@ -22,6 +23,9 @@ public class KubeConfigMessage {
    @JsonProperty("imagePullSecrets")
    private List<ImagePullSecret> imagePullSecrets;

    @JsonProperty("kubeconfigSecrets")
    private List<KubeconfigSecret> kubeconfigSecrets;

    @JsonProperty("kubeConfigAsBase64")
    private String kubeConfigAsBase64;

+50 −7
Changes for src/main/java/org/etsi/osl/hypo/registry/service/RegistryService.java: 50 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import org.etsi.osl.hypo.registry.model.kafka.incoming.RegistryURLRequest;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.ImagePullSecret;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.KafkaResponsePayload;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.KubeConfigResponseMessage;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.KubeconfigSecret;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.PackageRegistrySecretResponseMessage;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.RepoCredentials;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.Status;
@@ -197,6 +198,10 @@ public class RegistryService {
        List<ImagePullSecret> imagePullSecrets = retrieveImagePullSecrets(request, vaultToken, group);
        kubeConfigMessage.setImagePullSecrets(imagePullSecrets);

        List<KubeconfigSecret> kubeconfigSecrets =
                retrieveKubeconfigSecrets(request, vaultToken, group);
        kubeConfigMessage.setKubeconfigSecrets(kubeconfigSecrets);

        logger.debugf("Successfully built deployment KubeConfig response for ServiceID: %s", serviceID);
        return buildKubeConfigResponseMessage(
                request, kubeConfigMessage, serviceID, Status.SUCCESS, "");
@@ -880,6 +885,33 @@ public class RegistryService {
        return result;
    }

    private List<KubeconfigSecret> retrieveKubeconfigSecrets(
            KubeConfigRequest request, String vaultToken, String group) {
        if (request.getKubeconfigSecretIds() == null || request.getKubeconfigSecretIds().isEmpty()) {
            logger.debug(
                    "No kubeconfigSecretIds provided in request, skipping kubeconfig secret retrieval.");
            return Collections.emptyList();
        }

        List<KubeconfigSecret> result = new ArrayList<>();
        for (String kubeconfigSecretId : request.getKubeconfigSecretIds()) {
            Optional<String> kubeConfigAsBase64 =
                    retrieveKubeConfigAsBase64(vaultToken, kubeconfigSecretId, group);

            if (kubeConfigAsBase64.isEmpty()) {
                logger.warnf(
                        "Kubeconfig secret requested but not found for kubeconfigSecretId: %s",
                        kubeconfigSecretId);
            } else {
                KubeconfigSecret kubeconfigSecret = new KubeconfigSecret();
                kubeconfigSecret.setId(kubeconfigSecretId);
                kubeconfigSecret.setKubeConfigAsBase64(kubeConfigAsBase64.get());
                result.add(kubeconfigSecret);
            }
        }
        return result;
    }

    private void storeSchedulerNamespace(
            String serviceID, String group, String schedulerNamespace, String keycloakTokenStr) {
        Map<String, String> metadataMap = new HashMap<>();
@@ -930,6 +962,23 @@ public class RegistryService {

    private Optional<KubeConfigMessage> getKubeConfigMessage(
            KubeConfigRequest request, String vaultToken, String clusterIdentifier, String group) {
        Optional<String> kubeConfigAsBase64 =
                retrieveKubeConfigAsBase64(vaultToken, clusterIdentifier, group);
        if (kubeConfigAsBase64.isEmpty()) {
            return Optional.empty();
        }

        KubeConfigMessage data = new KubeConfigMessage();
        data.setId(UUID.randomUUID().toString());
        data.setType(request.getType());
        data.setServiceOperationRequest(request.getServiceOperationRequest());
        data.setKubeConfigAsBase64(kubeConfigAsBase64.get());

        return Optional.of(data);
    }

    private Optional<String> retrieveKubeConfigAsBase64(
            String vaultToken, String clusterIdentifier, String group) {
        Optional<Map<String, Object>> kubeSecret;
        String resolvedPath;
        if (group != null) {
@@ -963,13 +1012,7 @@ public class RegistryService {
            return Optional.empty();
        }

        KubeConfigMessage data = new KubeConfigMessage();
        data.setId(UUID.randomUUID().toString());
        data.setType(request.getType());
        data.setServiceOperationRequest(request.getServiceOperationRequest());
        data.setKubeConfigAsBase64(kubeConfigAsBase64);

        return Optional.of(data);
        return Optional.of(kubeConfigAsBase64);
    }

    private void sendKafkaMessageCallback(
+54 −0
Changes for src/test/java/org/etsi/osl/hypo/registry/service/RegistryServiceTest.java: 54 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import static org.etsi.osl.hypo.registry.config.ApplicationProperties.UNKNOWN;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.endsWith;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
@@ -62,6 +63,7 @@ import org.etsi.osl.hypo.registry.model.kafka.incoming.KubeConfigRequest;
import org.etsi.osl.hypo.registry.model.kafka.incoming.RegistryURLRequest;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.ImagePullSecret;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.KubeConfigResponseMessage;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.KubeconfigSecret;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.PackageRegistrySecretResponseMessage;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.RepoCredentials;
import org.etsi.osl.hypo.registry.model.kafka.outgoing.Status;
@@ -289,6 +291,58 @@ class RegistryServiceTest {
        assertThat(response.getData().getImagePullSecrets()).isEmpty();
    }

    @Test
    void getDeploymentKubeConfigResponseMessage_WithKubeconfigSecretIds() {
        // Arrange
        String hubKubeConfig = Base64.getEncoder().encodeToString("hub-kubeconf".getBytes());
        String managedKubeConfig = Base64.getEncoder().encodeToString("managed-1-kubeconf".getBytes());

        when(vaultService.getSecretWithVaultToken(anyString(), anyString()))
                .thenReturn(Optional.empty());
        when(vaultService.getSecretWithVaultToken(endsWith("/k8s-svc-id"), anyString()))
                .thenReturn(Optional.of(Map.of(RegistryService.KUBE_CONFIG_KEY, hubKubeConfig)));
        when(vaultService.getSecretWithVaultToken(endsWith("/managed-id-1"), anyString()))
                .thenReturn(Optional.of(Map.of(RegistryService.KUBE_CONFIG_KEY, managedKubeConfig)));

        kubeConfigRequest.setSecretNames(null);
        kubeConfigRequest.setKubeconfigSecretIds(List.of("managed-id-1", "managed-id-missing"));

        // Act
        KubeConfigResponseMessage response =
                registryService.getDeploymentKubeConfigResponseMessage(
                        kubeConfigRequest, KEYCLOAK_TOKEN_WITH_GROUP);

        // Assert
        assertThat(response.getStatus()).isEqualTo(Status.SUCCESS);
        assertThat(response.getData().getKubeConfigAsBase64()).isEqualTo(hubKubeConfig);

        List<KubeconfigSecret> kubeconfigSecrets = response.getData().getKubeconfigSecrets();
        assertThat(kubeconfigSecrets).hasSize(1);
        assertThat(kubeconfigSecrets.get(0).getId()).isEqualTo("managed-id-1");
        assertThat(kubeconfigSecrets.get(0).getKubeConfigAsBase64()).isEqualTo(managedKubeConfig);
    }

    @Test
    void getDeploymentKubeConfigResponseMessage_WithoutKubeconfigSecretIds() {
        // Arrange
        String hubKubeConfig = Base64.getEncoder().encodeToString("hub-kubeconf".getBytes());
        when(vaultService.getSecretWithVaultToken(anyString(), anyString()))
                .thenReturn(Optional.of(Map.of(RegistryService.KUBE_CONFIG_KEY, hubKubeConfig)))
                .thenReturn(Optional.empty());

        kubeConfigRequest.setSecretNames(null);
        kubeConfigRequest.setKubeconfigSecretIds(null);

        // Act
        KubeConfigResponseMessage response =
                registryService.getDeploymentKubeConfigResponseMessage(
                        kubeConfigRequest, KEYCLOAK_TOKEN_WITH_GROUP);

        // Assert
        assertThat(response.getStatus()).isEqualTo(Status.SUCCESS);
        assertThat(response.getData().getKubeconfigSecrets()).isEmpty();
    }

    @Test
    void getDeploymentKubeConfigResponseMessage_FailsWithInvalidTokenString() {
        assertThrows(