/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
package org.onap.cps.ncmp.api.impl.inventory.sync;
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME;
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR;
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
+import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.api.CpsAdminService;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.cps.api.CpsAnchorService;
+import org.onap.cps.api.CpsDataService;
import org.onap.cps.api.CpsModuleService;
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries;
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
+import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
+import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
import org.onap.cps.spi.CascadeDeleteAllowed;
+import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
+import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleReference;
+import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Service;
@Slf4j
private final DmiModelOperations dmiModelOperations;
private final CpsModuleService cpsModuleService;
-
- private final CpsAdminService cpsAdminService;
+ private final CmHandleQueries cmHandleQueries;
+ private final CpsDataService cpsDataService;
+ private final CpsAnchorService cpsAnchorService;
+ private final JsonObjectMapper jsonObjectMapper;
+ private final Map<String, Collection<ModuleReference>> moduleSetTagCache;
+ private static final Map<String, String> NO_NEW_MODULES = Collections.emptyMap();
/**
* This method registers a cm handle and initiates modules sync.
*
* @param yangModelCmHandle the yang model of cm handle.
*/
- public void syncAndCreateSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) {
+ public void syncAndCreateOrUpgradeSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) {
- final Collection<ModuleReference> allModuleReferencesFromCmHandle =
- dmiModelOperations.getModuleReferences(yangModelCmHandle);
+ final String cmHandleId = yangModelCmHandle.getId();
+ final CompositeState compositeState = yangModelCmHandle.getCompositeState();
+ final boolean inUpgrade = ModuleOperationsUtils.isInUpgradeOrUpgradeFailed(compositeState);
+ final String moduleSetTag = getModuleSetTag(yangModelCmHandle, compositeState, inUpgrade);
- final Collection<ModuleReference> identifiedNewModuleReferencesFromCmHandle = cpsModuleService
- .identifyNewModuleReferences(allModuleReferencesFromCmHandle);
+ final Collection<ModuleReference> moduleReferencesFromCache = moduleSetTagCache.get(moduleSetTag);
- final Map<String, String> newModuleNameToContentMap;
- if (identifiedNewModuleReferencesFromCmHandle.isEmpty()) {
- newModuleNameToContentMap = Collections.emptyMap();
+ if (moduleReferencesFromCache == null) {
+ final Optional<DataNode> existingCmHandleWithSameModuleSetTag
+ = getFirstReadyDataNodeWithModuleSetTag(moduleSetTag);
+
+ if (existingCmHandleWithSameModuleSetTag.isPresent()) {
+ final String existingAnchorName = existingCmHandleWithSameModuleSetTag.get().getAnchorName();
+ final Collection<ModuleReference> moduleReferencesFromExistingCmHandle =
+ upgradeOrCreateSchemaSetUsingModuleSetTag(yangModelCmHandle.getId(), moduleSetTag,
+ existingAnchorName, inUpgrade);
+ updateModuleSetTagCache(moduleSetTag, moduleReferencesFromExistingCmHandle);
+ } else {
+ if (inUpgrade) {
+ deleteSchemaSetIfExists(cmHandleId);
+ }
+ final Collection<ModuleReference> allModuleReferencesFromCmHandle
+ = syncAndCreateSchemaSet(yangModelCmHandle);
+ updateModuleSetTagCache(moduleSetTag, allModuleReferencesFromCmHandle);
+ }
} else {
- newModuleNameToContentMap = dmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle,
- identifiedNewModuleReferencesFromCmHandle);
+ if (inUpgrade) {
+ cpsModuleService.upgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId,
+ NO_NEW_MODULES, moduleReferencesFromCache);
+ } else {
+ cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
+ cmHandleId, NO_NEW_MODULES, moduleReferencesFromCache);
+ }
}
- createSchemaSetAndAnchor(yangModelCmHandle, newModuleNameToContentMap, allModuleReferencesFromCmHandle);
- }
-
- private void createSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle,
- final Map<String, String> newModuleNameToContentMap,
- final Collection<ModuleReference> allModuleReferencesFromCmHandle) {
- final String schemaSetAndAnchorName = yangModelCmHandle.getId();
- cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetAndAnchorName,
- newModuleNameToContentMap, allModuleReferencesFromCmHandle);
- cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetAndAnchorName,
- schemaSetAndAnchorName);
+ if (!inUpgrade) {
+ cpsAnchorService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId, cmHandleId);
+ }
+ setCmHandleModuleSetTag(yangModelCmHandle, moduleSetTag);
}
/**
}
}
+ private Optional<DataNode> getFirstReadyDataNodeWithModuleSetTag(final String moduleSetTag) {
+ final List<DataNode> dataNodes = StringUtils.isNotBlank(moduleSetTag) ? cmHandleQueries
+ .queryNcmpRegistryByCpsPath("//cm-handles[@module-set-tag='" + moduleSetTag + "']",
+ FetchDescendantsOption.OMIT_DESCENDANTS) : Collections.emptyList();
+ return dataNodes.stream().filter(dataNode -> {
+ final String cmHandleId = YangDataConverter.extractCmHandleIdFromXpath(dataNode.getXpath());
+ return cmHandleQueries.cmHandleHasState(cmHandleId, CmHandleState.READY);
+ }).findFirst();
+ }
+
+ private void setCmHandleModuleSetTag(final YangModelCmHandle upgradedCmHandle, final String moduleSetTag) {
+ final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1);
+ final Map<String, String> cmHandleProperties = new HashMap<>(2);
+ cmHandleProperties.put("id", upgradedCmHandle.getId());
+ cmHandleProperties.put("module-set-tag", moduleSetTag);
+ dmiRegistryProperties.put("cm-handles", cmHandleProperties);
+ cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
+ jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now());
+ }
+
+ private Collection<ModuleReference> syncAndCreateSchemaSet(final YangModelCmHandle yangModelCmHandle) {
+ final Collection<ModuleReference> allModuleReferencesFromCmHandle =
+ dmiModelOperations.getModuleReferences(yangModelCmHandle);
+ final Collection<ModuleReference> identifiedNewModuleReferencesFromCmHandle = cpsModuleService
+ .identifyNewModuleReferences(allModuleReferencesFromCmHandle);
+ final Map<String, String> newModuleNameToContentMap;
+ if (identifiedNewModuleReferencesFromCmHandle.isEmpty()) {
+ newModuleNameToContentMap = NO_NEW_MODULES;
+ } else {
+ newModuleNameToContentMap = dmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle,
+ identifiedNewModuleReferencesFromCmHandle);
+ }
+ cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
+ yangModelCmHandle.getId(), newModuleNameToContentMap, allModuleReferencesFromCmHandle);
+ return allModuleReferencesFromCmHandle;
+ }
+
+ private Collection<ModuleReference> upgradeOrCreateSchemaSetUsingModuleSetTag(final String schemaSetName,
+ final String moduleSetTag,
+ final String existingAnchorName,
+ final boolean inUpgrade) {
+ log.info("Found cm handle having module set tag: {}", moduleSetTag);
+ final Collection<ModuleReference> moduleReferencesFromExistingCmHandle =
+ cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
+ existingAnchorName);
+ if (inUpgrade) {
+ cpsModuleService.upgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
+ NO_NEW_MODULES, moduleReferencesFromExistingCmHandle);
+ } else {
+ cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
+ schemaSetName, NO_NEW_MODULES, moduleReferencesFromExistingCmHandle);
+ }
+ return moduleReferencesFromExistingCmHandle;
+ }
+
+ private String getModuleSetTag(final YangModelCmHandle yangModelCmHandle,
+ final CompositeState compositeState,
+ final boolean inUpgrade) {
+ if (inUpgrade) {
+ return ModuleOperationsUtils.getUpgradedModuleSetTagFromLockReason(compositeState.getLockReason());
+ }
+ return yangModelCmHandle.getModuleSetTag();
+ }
+
+ private void updateModuleSetTagCache(final String moduleSetTag,
+ final Collection<ModuleReference> allModuleReferencesFromCmHandle) {
+ if (StringUtils.isNotBlank(moduleSetTag)) {
+ moduleSetTagCache.putIfAbsent(moduleSetTag, allModuleReferencesFromCmHandle);
+ }
+ }
+
}