- Split bulkUpdateCmHandleStatesAndProperties and updateCmHandleFields to perform separate tasks
- updateCmHandleFields updates fields in previous use cases
- bulkUpdateCmHandleStatesAndProperties only updates fields for migration purposes
- Added dmiProperties to CmHandleStateAndDmiPropertiesUpdate
- Added convertAdditionalPropertiesToJson to convert additionalProperties to dmiProperties
Issue-ID: CPS-3063
Change-Id: I7560a289150147d1cda40e75a41d52c2723316e8
Signed-off-by: egernug <gerard.nugent@est.tech>
import org.onap.cps.api.parameters.FetchDescendantsOption;
import org.onap.cps.ncmp.api.inventory.models.CompositeState;
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
-import org.onap.cps.ncmp.impl.models.CmHandleStateUpdate;
+import org.onap.cps.ncmp.impl.models.CmHandleMigrationDetail;
public interface InventoryPersistence extends NcmpPersistence {
/**
* Method to update a batch of cm handles status to the value in CompositeState.
*
- * @param cmHandleStateUpdates the cmHandleId and state change being performed on it
+ * @param cmHandleMigrationDetails the cmHandleId and state or dimProperties
+ * change being performed on it
*/
- void bulkUpdateCmHandleStates(List<CmHandleStateUpdate> cmHandleStateUpdates);
+ void cmHandleBulkMigrate(
+ List<CmHandleMigrationDetail> cmHandleMigrationDetails);
}
import org.onap.cps.ncmp.api.inventory.models.CompositeState;
import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder;
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
-import org.onap.cps.ncmp.impl.models.CmHandleStateUpdate;
+import org.onap.cps.ncmp.impl.models.CmHandleMigrationDetail;
import org.onap.cps.ncmp.impl.utils.YangDataConverter;
import org.onap.cps.utils.ContentType;
import org.onap.cps.utils.CpsValidator;
@Override
public void updateCmHandleFields(final String fieldName, final Map<String, String> newValuePerCmHandleId) {
if (!newValuePerCmHandleId.isEmpty()) {
- final Map<String, Object> targetCmHandleStatePerCmHandleId = new HashMap<>();
- final List<Map<String, String>> targetCmHandleStatesPerCmHandleIds = new ArrayList<>();
-
+ final List<Map<String, String>> targetCmHandleFieldChangesPerCmHandleIds = new ArrayList<>();
for (final Map.Entry<String, String> entry : newValuePerCmHandleId.entrySet()) {
final Map<String, String> cmHandleData = new HashMap<>();
cmHandleData.put("id", entry.getKey());
cmHandleData.put(fieldName, entry.getValue());
- targetCmHandleStatesPerCmHandleIds.add(cmHandleData);
+ targetCmHandleFieldChangesPerCmHandleIds.add(cmHandleData);
log.debug("Updating {} for cmHandle {} to {}", fieldName, entry.getKey(), entry.getValue());
}
- targetCmHandleStatePerCmHandleId.put("cm-handles", targetCmHandleStatesPerCmHandleIds);
cpsDataService.updateNodeLeaves(
NCMP_DATASPACE_NAME,
NCMP_DMI_REGISTRY_ANCHOR,
NCMP_DMI_REGISTRY_PARENT,
- jsonObjectMapper.asJsonString(targetCmHandleStatePerCmHandleId),
+ jsonObjectMapper.asJsonString(Map.of("cm-handles", targetCmHandleFieldChangesPerCmHandleIds)),
OffsetDateTime.now(),
ContentType.JSON);
+
}
}
@Override
- public void bulkUpdateCmHandleStates(final List<CmHandleStateUpdate> cmHandleStateUpdates) {
- final Map<String, String> mappedCmHandleStateUpdates = cmHandleStateUpdates.stream()
- .collect(Collectors.toMap(
- CmHandleStateUpdate::cmHandleId,
- CmHandleStateUpdate::state
- ));
- updateCmHandleFields("cm-handle-state", mappedCmHandleStateUpdates);
+ public void cmHandleBulkMigrate(
+ final List<CmHandleMigrationDetail> cmHandleMigrationDetails) {
+ if (cmHandleMigrationDetails.isEmpty()) {
+ return;
+ }
+ final List<Map<String, String>> cmHandleMigrationDetailAsMaps =
+ new ArrayList<>(cmHandleMigrationDetails.size());
+ for (final CmHandleMigrationDetail cmHandleMigrationDetail : cmHandleMigrationDetails) {
+ final Map<String, String> cmHandleMigrationDetailAsMap = new HashMap<>();
+ cmHandleMigrationDetailAsMap.put("id", cmHandleMigrationDetail.cmHandleId());
+ cmHandleMigrationDetailAsMap.put("cm-handle-state", cmHandleMigrationDetail.state());
+ if (cmHandleMigrationDetail.dmiProperties() != null) {
+ cmHandleMigrationDetailAsMap.put("dmi-properties", cmHandleMigrationDetail.dmiProperties());
+ }
+ cmHandleMigrationDetailAsMaps.add(cmHandleMigrationDetailAsMap);
+ }
+ cpsDataService.updateNodeLeaves(
+ NCMP_DATASPACE_NAME,
+ NCMP_DMI_REGISTRY_ANCHOR,
+ NCMP_DMI_REGISTRY_PARENT,
+ jsonObjectMapper.asJsonString(Map.of("cm-handles", cmHandleMigrationDetailAsMaps)),
+ OffsetDateTime.now(),
+ ContentType.JSON);
}
private static String getXPathForCmHandleById(final String cmHandleId) {
package org.onap.cps.ncmp.impl.models;
-public record CmHandleStateUpdate (String cmHandleId, String state) {}
+public record CmHandleMigrationDetail(String cmHandleId, String state, String dmiProperties) {}
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade;
import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService;
import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.impl.models.CmHandleStateUpdate;
+import org.onap.cps.ncmp.impl.models.CmHandleMigrationDetail;
+import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Component;
@Slf4j
@RequiredArgsConstructor
public class DataMigration {
- public final InventoryPersistence inventoryPersistence;
+ private final InventoryPersistence inventoryPersistence;
private final CmHandleQueryService cmHandleQueryService;
private final NetworkCmProxyInventoryFacade networkCmProxyInventoryFacade;
+ private final JsonObjectMapper jsonObjectMapper;
/**
private void migrateBatch(final List<String> cmHandleIds) {
log.debug("Processing batch of {} Cm Handles", cmHandleIds.size());
- final List<CmHandleStateUpdate> cmHandleStateUpdates = new ArrayList<>();
+ final List<CmHandleMigrationDetail> cmHandleMigrationDetails =
+ new ArrayList<>(cmHandleIds.size());
for (final String cmHandleId : cmHandleIds) {
try {
final NcmpServiceCmHandle ncmpServiceCmHandle =
networkCmProxyInventoryFacade.getNcmpServiceCmHandle(cmHandleId);
- final String valueFromOldModel = ncmpServiceCmHandle.getCompositeState().getCmHandleState().name();
- cmHandleStateUpdates.add(new CmHandleStateUpdate(
+ cmHandleMigrationDetails.add(new CmHandleMigrationDetail(
ncmpServiceCmHandle.getCmHandleId(),
- valueFromOldModel
+ ncmpServiceCmHandle.getCompositeState().getCmHandleState().name(),
+ convertAdditionalPropertiesToJson(ncmpServiceCmHandle.getAdditionalProperties())
));
} catch (final Exception e) {
log.error("Failed to process CM handle {} state", cmHandleId, e);
}
}
try {
- inventoryPersistence.bulkUpdateCmHandleStates(cmHandleStateUpdates);
+ inventoryPersistence.cmHandleBulkMigrate(cmHandleMigrationDetails);
log.debug("Successfully updated Cm Handles");
} catch (final Exception e) {
log.error("Failed to perform bulk update for batch", e);
}
}
+
+ private String convertAdditionalPropertiesToJson(final Map<String, String> additionalProperties) {
+ return jsonObjectMapper.asJsonString(additionalProperties);
+ }
}
import org.onap.cps.ncmp.api.inventory.models.CmHandleState
import org.onap.cps.ncmp.api.inventory.models.CompositeState
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
-import org.onap.cps.ncmp.impl.models.CmHandleStateUpdate
+import org.onap.cps.ncmp.impl.models.CmHandleMigrationDetail
import org.onap.cps.utils.ContentType
import org.onap.cps.utils.CpsValidator
import org.onap.cps.utils.JsonObjectMapper
def cmHandleId = 'ch-1'
def updates = [
- new CmHandleStateUpdate("ch-1", "READY"),
- new CmHandleStateUpdate("ch-2", "DELETING")
+ new CmHandleMigrationDetail("ch-1", "READY", "some-dmi-properties"),
+ new CmHandleMigrationDetail("ch-2", "DELETING", "some-dmi-properties")
]
def alternateId = 'some-alternate-id'
def leaves = ["id":cmHandleId, "alternateId":alternateId,"dmi-service-name":"common service name","dmi-data-service-name":"data service name","dmi-model-service-name":"model service name"]
when: 'update is called.'
objectUnderTest.updateCmHandleField('ch-1', 'my field', 'my new value')
then: 'call is delegated to updateCmHandleFields'
- 1 * objectUnderTest.updateCmHandleFields('my field', ['ch-1':'my new value'])
+ 1 * objectUnderTest.updateCmHandleFields('my field', ['ch-1':'my new value'])
}
def 'Bulk update cm handle state.'(){
when: 'bulk update is called'
- objectUnderTest.bulkUpdateCmHandleStates(updates)
+ objectUnderTest.cmHandleBulkMigrate(updates)
then: 'call is made to update the fileds of the cm handle'
- 1 * objectUnderTest.updateCmHandleFields('cm-handle-state', ['ch-1':'READY','ch-2':'DELETING'])
+ 1 * mockCpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT, { jsonString ->
+ jsonString.contains('"cm-handle-state":"READY"') && jsonString.contains('"cm-handle-state":"DELETING"')
+ }, _, ContentType.JSON)
+ }
+
+ def 'Bulk update with empty list.'() {
+ when: 'bulk update is called with empty list'
+ objectUnderTest.cmHandleBulkMigrate([])
+ then: 'no database call is made'
+ 0 * mockCpsDataService.updateNodeLeaves(*_)
}
}
import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.read.ListAppender
+import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
import org.onap.cps.ncmp.api.inventory.models.CompositeState
import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService
import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.utils.JsonObjectMapper
import org.slf4j.LoggerFactory
import spock.lang.Specification
import spock.lang.Subject
def mockCmHandleQueryService = Mock(CmHandleQueryService)
def mockNetworkCmProxyInventoryFacade = Mock(NetworkCmProxyInventoryFacade)
def mockInventoryPersistence = Mock(InventoryPersistence)
- def cmHandle1 = new NcmpServiceCmHandle(cmHandleId: 'ch-1', dmiServiceName: 'dmi1', compositeState: new CompositeState(cmHandleState: READY))
- def cmHandle2 = new NcmpServiceCmHandle(cmHandleId: 'ch-2', dmiServiceName: 'dmi1', compositeState: new CompositeState(cmHandleState: ADVISED))
- def cmHandle3 = new NcmpServiceCmHandle(cmHandleId: 'ch-3', dmiServiceName: 'dmi2', compositeState: new CompositeState(cmHandleState: READY))
-
+ def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ def cmHandleWithAdditionalProperty = new NcmpServiceCmHandle(cmHandleId: 'ch-1', dmiServiceName: 'dmi1', compositeState: new CompositeState(cmHandleState: READY), additionalProperties: [id: '4'])
+ def cmHandleWithAdditionalPropertyEmpty = new NcmpServiceCmHandle(cmHandleId: 'ch-2', dmiServiceName: 'dmi1', compositeState: new CompositeState(cmHandleState: ADVISED), additionalProperties: [:])
+ def cmHandleWithAdditionalPropertyNull = new NcmpServiceCmHandle(cmHandleId: 'ch-3', dmiServiceName: 'dmi2', compositeState: new CompositeState(cmHandleState: READY), additionalProperties: null)
def logger = Spy(ListAppender<ILoggingEvent>)
def setup() {
- mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('ch-1') >> cmHandle1
- mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('ch-2') >> cmHandle2
- mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('ch-3') >> cmHandle3
+ mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('ch-1') >> cmHandleWithAdditionalProperty
+ mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('ch-2') >> cmHandleWithAdditionalPropertyEmpty
+ mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('ch-3') >> cmHandleWithAdditionalPropertyNull
setupLogger(Level.ERROR)
}
@Subject
- def objectUnderTest = Spy(new DataMigration(mockInventoryPersistence, mockCmHandleQueryService, mockNetworkCmProxyInventoryFacade))
+ def objectUnderTest = Spy(new DataMigration(mockInventoryPersistence, mockCmHandleQueryService, mockNetworkCmProxyInventoryFacade, jsonObjectMapper))
def 'CM Handle migration.'() {
given: 'a list of CM handle IDs'
when: 'migration is performed'
objectUnderTest.migrateInventoryToModelRelease20250722(3)
then: 'handles are processed in bulk'
- 1 * mockInventoryPersistence.bulkUpdateCmHandleStates({ cmHandleStateUpdates ->
- def actualData = cmHandleStateUpdates.collect { [id: it.cmHandleId, state: it.state] }
+ 1 * mockInventoryPersistence.cmHandleBulkMigrate({ cmHandleStateUpdates ->
+ def actualData = cmHandleStateUpdates.collect { [id: it.cmHandleId, state: it.state, dmiProperties: it.dmiProperties] }
assert actualData.size() == 3
- assert actualData.containsAll([
- [id: 'ch-1', state: 'READY'],
- [id: 'ch-2', state: 'ADVISED'],
- [id: 'ch-3', state: 'READY']
- ])
+ assert actualData[0].id == 'ch-1'
+ assert actualData[0].state == 'READY'
+ assert actualData[0].dmiProperties == '{"id":"4"}'
+ assert actualData[1].id == 'ch-2'
+ assert actualData[1].state == 'ADVISED'
+ assert actualData[1].dmiProperties == '{}'
+ assert actualData[2].id == 'ch-3'
+ assert actualData[2].state == 'READY'
+ assert actualData[2].dmiProperties == 'null'
})
}
when: 'migration is performed'
objectUnderTest.migrateInventoryToModelRelease20250722(2)
then: 'migration processes no batches'
- 1 * mockInventoryPersistence.bulkUpdateCmHandleStates([])
+ 1 * mockInventoryPersistence.cmHandleBulkMigrate([])
}
def 'Migrate batch with error.'() {
def cmHandleIds = ['ch-1']
mockCmHandleQueryService.getAllCmHandleReferences(false) >> cmHandleIds
and: 'an exception happens updating cm handle states'
- mockInventoryPersistence.bulkUpdateCmHandleStates(*_) >> {
+ mockInventoryPersistence.cmHandleBulkMigrate(*_) >> {
throw new RuntimeException('Simulated failure')
}
when: 'migration is performed'
schema:
type: object
description: OK
+ "204":
+ content:
+ application/json:
+ schema:
+ example: my-resource
+ type: string
+ description: Created
"400":
content:
application/json: