From: KrupaNagabhushan Date: Thu, 4 Dec 2025 13:02:43 +0000 (+0000) Subject: TEIV: Adding error handling and caching to FOCOM X-Git-Tag: 0.3.0~2 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=509db31b86e4735ba086dc14c6b909ebe5201dd7;p=smo%2Fteiv.git TEIV: Adding error handling and caching to FOCOM Issue-ID: SMO-208 Change-Id: Iac66177326d4407bd8c8903bd6f3507c94c84f67 Signed-off-by: KrupaNagabhushan --- diff --git a/adapters/focom-to-teiv-adapter/pom.xml b/adapters/focom-to-teiv-adapter/pom.xml index ed2243c..21d4ab1 100644 --- a/adapters/focom-to-teiv-adapter/pom.xml +++ b/adapters/focom-to-teiv-adapter/pom.xml @@ -94,6 +94,10 @@ ${sundr.builder.version} provided + + org.testcontainers + testcontainers + @@ -150,6 +154,17 @@ src/main/resources/crds + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + diff --git a/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/FocomToTeivIngestion.java b/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/FocomToTeivIngestion.java index 0a92a10..174f0fe 100644 --- a/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/FocomToTeivIngestion.java +++ b/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/FocomToTeivIngestion.java @@ -27,8 +27,10 @@ import lombok.extern.slf4j.Slf4j; import org.oran.smo.teiv.adapters.focom_to_teiv_adapter.service.FocomToTeivModelBuilder; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import org.testcontainers.shaded.com.google.common.hash.Hashing; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Map; @Slf4j @@ -38,14 +40,30 @@ public class FocomToTeivIngestion { private static final ObjectMapper objectMapper = new ObjectMapper(); private final KafkaEventProducer kafkaEventProducer; - private final FocomToTeivModelBuilder jsonBuilder; + private final FocomToTeivModelBuilder focomToTeivModelBuilder; + + private String lastPayloadHash = null; @Scheduled(fixedRateString = "${polling.interval}") public void pollExternalApi() throws IOException { - Map json = jsonBuilder.getFocomtoTeivJson(); - log.debug("Retrieved JSON for FOCOM_PROVISION_REQUEST_NAME: {}", json); + Map modelJson = focomToTeivModelBuilder.getFocomtoTeivJson(); + if (modelJson == null || modelJson.isEmpty()) { + log.info("FOCOM JSON is empty. CloudEvent will NOT be sent."); + return; + } + log.debug("Retrieved JSON for FOCOM_PROVISION_REQUEST_NAME: {}", modelJson); + + String newPayload = objectMapper.writeValueAsString(modelJson); + String newPayloadHash = Hashing.sha256().hashString(newPayload, StandardCharsets.UTF_8).toString(); + + if (newPayloadHash.equals(lastPayloadHash)) { + log.info("No change detected in CR. Skipping CloudEvent."); + return; + } + try { - sendCloudEvent(json, "merge"); + sendCloudEvent(modelJson, "merge"); + lastPayloadHash = newPayloadHash; } catch (IOException e) { log.error("Failed to poll external API or send CloudEvent", e); } diff --git a/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/custom_resource_json/EntityItem.java b/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/custom_resource_json/EntityItem.java index c1facce..00e88d9 100644 --- a/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/custom_resource_json/EntityItem.java +++ b/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/custom_resource_json/EntityItem.java @@ -32,4 +32,9 @@ public class EntityItem { @JsonProperty("attributes") private Map attributes; + + public boolean isEmpty() { + return (id == null || id.isBlank()) && + (attributes == null || attributes.isEmpty()); + } } diff --git a/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/service/FocomToTeivModelBuilder.java b/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/service/FocomToTeivModelBuilder.java index 1271fd1..721c6e9 100644 --- a/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/service/FocomToTeivModelBuilder.java +++ b/adapters/focom-to-teiv-adapter/src/main/java/org/oran/smo/teiv/adapters/focom_to_teiv_adapter/service/FocomToTeivModelBuilder.java @@ -22,6 +22,7 @@ package org.oran.smo.teiv.adapters.focom_to_teiv_adapter.service; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import io.fabric8.kubernetes.client.KubernetesClientException; import lombok.extern.slf4j.Slf4j; import org.nephio.focom.v1alpha1.FocomProvisioningRequest; import org.oran.provisioning.o2ims.v1alpha1.ProvisioningRequest; @@ -32,10 +33,11 @@ import org.oran.smo.teiv.adapters.focom_to_teiv_adapter.custom_resource_json.Rel import org.springframework.stereotype.Component; import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.List; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; -import java.util.Map; import static org.oran.smo.teiv.adapters.common.utils.Constants.ENTITY_OCLOUD_NAMESPACE; @@ -63,10 +65,23 @@ public class FocomToTeivModelBuilder { List oCloudNamespaces = new ArrayList<>(); List nodeClusters = new ArrayList<>(); List deployOnRelationships = new ArrayList<>(); + List focomRequests; int index = 1; - List focomRequests = service.getAllFocomProvisioningRequests(); + try { + focomRequests = service.getAllFocomProvisioningRequests(); + } catch (KubernetesClientException e) { + log.error("Failed to retrieve FOCOM provisioning requests from Kubernetes: {}", e.getMessage(), e); + return Collections.emptyMap(); + } catch (Exception e) { + log.error("Unexpected error while retrieving FOCOM provisioning requests", e); + return Collections.emptyMap(); + } + + if (focomRequests == null || focomRequests.isEmpty()) { + return Collections.emptyMap(); + } for (FocomProvisioningRequest focomProvisioningRequest : focomRequests) { @@ -76,6 +91,11 @@ public class FocomToTeivModelBuilder { oCloudNamespaces.add(oCloudNamespace); EntityItem nodeCluster = buildNodeCluster(focomProvisioningRequest, index); + if (nodeCluster == null || nodeCluster.isEmpty()) { + log.error("Failed to build Nodecluster, attributes missing"); + index++; + continue; + } nodeClusters.add(nodeCluster); RelationshipItem rel = modelService.getTeivRelationshipDeployOn(oCloudNamespace, nodeCluster, index); @@ -89,20 +109,25 @@ public class FocomToTeivModelBuilder { buildEntityTypeName(SMO_TEIV_CLOUD_PREFIX, ENTITY_OCLOUD_NAMESPACE), oCloudNamespaces ); - entities.put( - buildEntityTypeName(SMO_TEIV_CLOUD_PREFIX, ENTITY_NODE_CLUSTER), - nodeClusters - ); + + if (!nodeClusters.isEmpty()) { + entities.put( + buildEntityTypeName(SMO_TEIV_CLOUD_PREFIX, ENTITY_NODE_CLUSTER), + nodeClusters + ); + } Map> relationships = new HashMap<>(); - relationships.put( - buildTeivFocomRelationshipTypeName( - REL_DEPLOYED_ON, - ENTITY_OCLOUD_NAMESPACE.toUpperCase(), - ENTITY_NODE_CLUSTER.toUpperCase() - ), - deployOnRelationships - ); + if (!deployOnRelationships.isEmpty()) { + relationships.put( + buildTeivFocomRelationshipTypeName( + REL_DEPLOYED_ON, + ENTITY_OCLOUD_NAMESPACE.toUpperCase(), + ENTITY_NODE_CLUSTER.toUpperCase() + ), + deployOnRelationships + ); + } EntityAndRelationshipModel entityAndRelationshipModel = new EntityAndRelationshipModel(); entityAndRelationshipModel.setEntities(List.of(entities)); @@ -128,14 +153,23 @@ public class FocomToTeivModelBuilder { } private EntityItem buildNodeCluster(FocomProvisioningRequest focomProvisioningRequest, int index) { - ProvisioningRequest o2imsReq = service.getO2imsProvisioningRequest(focomProvisioningRequest.getMetadata().getName()); + ProvisioningRequest o2imsRequest; + try { + o2imsRequest = service.getO2imsProvisioningRequest(focomProvisioningRequest.getMetadata().getName()); + } catch (KubernetesClientException e) { + log.error("Failed to retrieve O2ims provisioning requests from Kubernetes: {}", e.getMessage(), e); + return new EntityItem(); + } catch (Exception e) { + log.error("Unexpected error while retrieving O2ims provisioning requests", e); + return new EntityItem(); + } String clusterName = focomProvisioningRequest.getSpec().getTemplateParameters() .getAdditionalProperties() .get("clusterName") .toString(); - String nodeClusterId = String.valueOf(o2imsReq.getStatus() + String nodeClusterId = String.valueOf(o2imsRequest.getStatus() .getProvisionedResourceSet() .getOCloudNodeClusterId());