springframework: INFO\r
onap:\r
cps: INFO\r
-ncmp:\r
- dmi:\r
- auth:\r
- username: ${DMI_USERNAME}\r
- password: ${DMI_PASSWORD}\r
- api:\r
- base-path: dmi\r
- timers:\r
- advised-modules-sync:\r
- sleep-time-ms: 30000
\ No newline at end of file
+\r
+dmi:\r
+ auth:\r
+ username: ${DMI_USERNAME}\r
+ password: ${DMI_PASSWORD}\r
+ api:\r
+ base-path: dmi\r
+\r
+timers:\r
+ advised-modules-sync:\r
+ sleep-time-ms: 30000
\ No newline at end of file
@Getter
@Component
public static class DmiProperties {
- @Value("${ncmp.dmi.auth.username}")
+ @Value("${dmi.auth.username}")
private String authUsername;
- @Value("${ncmp.dmi.auth.password}")
+ @Value("${dmi.auth.password}")
private String authPassword;
- @Value("${ncmp.dmi.api.base-path}")
+ @Value("${dmi.api.base-path}")
private String dmiBasePath;
}
ncmpServiceCmHandle.setCmHandleId(cmHandleId);
populateCmHandleProperties(cmHandleDataNode, ncmpServiceCmHandle);
return YangModelCmHandle.toYangModelCmHandle(
- String.valueOf(cmHandleDataNode.getLeaves().get("dmi-service-name")),
- String.valueOf(cmHandleDataNode.getLeaves().get("dmi-data-service-name")),
- String.valueOf(cmHandleDataNode.getLeaves().get("dmi-model-service-name")),
+ (String) cmHandleDataNode.getLeaves().get("dmi-service-name"),
+ (String) cmHandleDataNode.getLeaves().get("dmi-data-service-name"),
+ (String) cmHandleDataNode.getLeaves().get("dmi-model-service-name"),
ncmpServiceCmHandle
);
}
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService;
-import org.onap.cps.ncmp.api.inventory.CmHandleState;
+import org.onap.cps.ncmp.api.inventory.CompositeState;
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
import org.onap.cps.utils.CpsValidator;
private String dmiDataServiceName;
@JsonProperty("state")
- private CmHandleState cmHandleState;
+ private CompositeState compositeState;
@JsonProperty("dmi-model-service-name")
private String dmiModelServiceName;
/**
* Create a yangModelCmHandle.
- * @param dmiServiceName dmi service name
- * @param dmiDataServiceName dmi data service name
+ *
+ * @param dmiServiceName dmi service name
+ * @param dmiDataServiceName dmi data service name
* @param dmiModelServiceName dmi model service name
* @param ncmpServiceCmHandle the cm handle
* @return instance of yangModelCmHandle
yangModelCmHandle.setDmiModelServiceName(dmiModelServiceName);
yangModelCmHandle.setDmiProperties(asYangModelCmHandleProperties(ncmpServiceCmHandle.getDmiProperties()));
yangModelCmHandle.setPublicProperties(asYangModelCmHandleProperties(
- ncmpServiceCmHandle.getPublicProperties()));
+ ncmpServiceCmHandle.getPublicProperties()));
return yangModelCmHandle;
}
/**
* Resolve a dmi service name.
+ *
* @param requiredService indicates what typo of service is required
* @return dmi service name
*/
package org.onap.cps.ncmp.api.inventory;
public enum CmHandleState {
-
- ADVISED {
- @Override
- public CmHandleState ready() {
- return READY;
- }
- },
- READY {
- @Override
- public CmHandleState ready() {
- return this;
- }
-
- };
-
- public abstract CmHandleState ready();
-
+ ADVISED, READY;
}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.inventory;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * State Model to store state corresponding to the Yang resource dmi-registry model.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class CompositeState {
+
+ @JsonProperty("cm-handle-state")
+ private CmHandleState cmhandleState;
+
+ @JsonProperty("lock-reason")
+ private LockReason lockReason;
+
+ @JsonProperty("last-update-time")
+ private String lastUpdateTime;
+
+ @JsonProperty("data-sync-enabled")
+ private Boolean dataSyncEnabled;
+
+ @JsonProperty("datastores")
+ private DataStores dataStores;
+
+ @Data
+ @Builder
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public static class LockReason {
+
+ @JsonProperty("reason")
+ private String reason;
+
+ @JsonProperty("details")
+ private String details;
+
+ }
+
+ @Data
+ @Builder
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public static class DataStores {
+
+ @JsonProperty("operational")
+ private Operational operationalDataStore;
+
+ @JsonProperty("running")
+ private Running runningDataStore;
+ }
+
+ @Data
+ @Builder
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public static class Operational {
+
+ @JsonProperty("sync-state")
+ private String syncState;
+
+ @JsonProperty("last-sync-time")
+ private String lastSyncTime;
+ }
+
+ @Data
+ @Builder
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public static class Running {
+
+ @JsonProperty("sync-state")
+ private String syncState;
+
+ @JsonProperty("last-sync-time")
+ private String lastSyncTime;
+ }
+
+}
/**
* Execute Cm Handle poll which changes the cm handle state from 'ADVISED' to 'READY'.
*/
- @Scheduled(fixedDelayString = "${ncmp.timers.advised-modules-sync.sleep-time-ms}")
+ @Scheduled(fixedDelayString = "${timers.advised-modules-sync.sleep-time-ms}")
public void executeAdvisedCmHandlePoll() {
YangModelCmHandle advisedCmHandle = syncUtils.getAnAdvisedCmHandle();
while (advisedCmHandle != null) {
- final CmHandleState cmHandleState = advisedCmHandle.getCmHandleState();
moduleSyncService.syncAndCreateSchemaSet(advisedCmHandle);
// ToDo Lock Cm Handle if module sync fails
- syncUtils.updateCmHandleState(advisedCmHandle, cmHandleState.ready());
- log.info("{} is now in {} state", advisedCmHandle.getId(), advisedCmHandle.getCmHandleState());
+ syncUtils.updateCmHandleState(advisedCmHandle, CmHandleState.READY);
+ log.info("{} is now in {} state", advisedCmHandle.getId(),
+ advisedCmHandle.getCompositeState().getCmhandleState());
advisedCmHandle = syncUtils.getAnAdvisedCmHandle();
}
log.debug("No Cm-Handles currently found in an ADVISED state");
* @param cmHandleState cm handle state
*/
public void updateCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState cmHandleState) {
- yangModelCmHandle.setCmHandleState(cmHandleState);
+ yangModelCmHandle.getCompositeState().setCmhandleState(cmHandleState);
final String cmHandleJsonData = String.format("{\"cm-handles\":[%s]}",
jsonObjectMapper.asJsonString(yangModelCmHandle));
cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
and: 'the result is not returned'
result == null
}
+
+ def "Handling missing service names as null CPS-1043."() {
+ given: 'the cps data service returns a data node from the DMI registry with empty child and leaf attributes'
+ def dataNode = new DataNode(childDataNodes:[], leaves: [:])
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> dataNode
+ when: 'retrieving the yang modelled cm handle'
+ def result = objectUnderTest.getYangModelCmHandle(cmHandleId)
+ then: 'the service names ae returned as null'
+ result.dmiServiceName == null
+ result.dmiDataServiceName == null
+ result.dmiModelServiceName == null
+ }
}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.inventory
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import spock.lang.Specification
+
+import java.time.OffsetDateTime
+import java.time.ZoneOffset
+import java.time.format.DateTimeFormatter
+
+import static CompositeState.DataStores
+import static CompositeState.LockReason
+import static CompositeState.Operational
+import static CompositeState.Running
+import static org.onap.cps.ncmp.utils.TestUtils.getResourceFileContent
+import static org.springframework.util.StringUtils.trimAllWhitespace
+
+class CompositeStateSpec extends Specification {
+
+ def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(OffsetDateTime.of(2022, 1, 1, 1, 1, 1, 1, ZoneOffset.MIN))
+ def objectMapper = new ObjectMapper()
+
+ def "Composite State Specification"() {
+ given: "a Composite State"
+ def compositeState = new CompositeState(cmhandleState: CmHandleState.ADVISED,
+ lockReason: LockReason.builder().reason('lock-reason').details("lock-misbehaving-details").build(),
+ lastUpdateTime: formattedDateAndTime.toString(),
+ dataSyncEnabled: false,
+ dataStores: dataStores())
+ when: 'it is represented as JSON'
+ def jsonStateModelAsString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(compositeState)
+ then: 'it matches expected state model as JSON'
+ def expectedStateModelAsjson = getResourceFileContent('expectedStateModel.json')
+ assert trimAllWhitespace(expectedStateModelAsjson) == trimAllWhitespace(jsonStateModelAsString)
+ }
+
+ def dataStores() {
+ DataStores.builder().operationalDataStore(Operational.builder()
+ .syncState('NONE_REQUESTED')
+ .lastSyncTime(formattedDateAndTime.toString()).build()).runningDataStore(Running.builder()
+ .syncState('NONE_REQUESTED')
+ .lastSyncTime(formattedDateAndTime.toString()).build())
+ .build()
+ }
+}
given: 'a cm handle with an ADVISED state'
def cmHandleState = CmHandleState.ADVISED
when: 'the state transitions to the READY state'
- cmHandleState = cmHandleState.ready()
+ cmHandleState = CmHandleState.READY
then: 'the cm handle state changes to READY'
assert CmHandleState.READY == cmHandleState
}
given: 'a cm handle with a READY state'
def cmHandleState = CmHandleState.READY
when: 'the state transitions to READY state'
- cmHandleState = cmHandleState.ready()
+ cmHandleState = CmHandleState.READY
then: 'the cm handle state remains as READY'
assert CmHandleState.READY == cmHandleState
}
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.ncmp.api.inventory.CmHandleState
+import org.onap.cps.ncmp.api.inventory.CompositeState
import spock.lang.Specification
class ModuleSyncSpec extends Specification {
def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handles'() {
given: 'cm handles in an advised state'
- def yangModelCmHandle1 = new YangModelCmHandle(cmHandleState: cmHandleState)
- def yangModelCmHandle2 = new YangModelCmHandle(cmHandleState: cmHandleState)
+ def compositeState = new CompositeState()
+ compositeState.cmhandleState = cmHandleState
+ def yangModelCmHandle1 = new YangModelCmHandle(compositeState: compositeState)
+ def yangModelCmHandle2 = new YangModelCmHandle(compositeState: compositeState)
and: 'sync utilities return a cm handle twice'
mockSyncUtils.getAnAdvisedCmHandle() >>> [yangModelCmHandle1, yangModelCmHandle2, null]
when: 'module sync poll is executed'
import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.ncmp.api.inventory.CmHandleState
+import org.onap.cps.ncmp.api.inventory.CompositeState
import org.onap.cps.spi.CpsDataPersistenceService
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.model.DataNode
def 'Update cm handle state from Advised to Ready'() {
given: 'a yang model cm handle and the expected json data'
- def yangModelCmHandle = new YangModelCmHandle(id: 'Some-Cm-Handle', cmHandleState: CmHandleState.ADVISED)
- def expectedJsonData = '{"cm-handles":[{"id":"Some-Cm-Handle","state":"READY"}]}'
+ def compositeState = new CompositeState()
+ compositeState.cmhandleState = CmHandleState.ADVISED
+ def yangModelCmHandle = new YangModelCmHandle(id: 'Some-Cm-Handle', compositeState: compositeState )
+ def expectedJsonData = '{"cm-handles":[{"id":"Some-Cm-Handle","state":{"cm-handle-state":"READY"}}]}'
when: 'update cm handle state is called'
objectUnderTest.updateCmHandleState(yangModelCmHandle, CmHandleState.READY)
then: 'update data note leaves is invoked with the correct params'
# SPDX-License-Identifier: Apache-2.0
# ============LICENSE_END=========================================================
-ncmp:
- dmi:
- auth:
- username: some-user
- password: some-password
- api:
- base-path: dmi
+dmi:
+ auth:
+ username: some-user
+ password: some-password
+ api:
+ base-path: dmi
--- /dev/null
+{
+ "cm-handle-state" : "ADVISED",
+ "lock-reason" : {
+ "reason" : "lock-reason",
+ "details" : "lock-misbehaving-details"
+ },
+ "last-update-time" : "2022-01-01T01:01:01.000-1800",
+ "data-sync-enabled" : false,
+ "datastores" : {
+ "operational" : {
+ "sync-state" : "NONE_REQUESTED",
+ "last-sync-time" : "2022-01-01T01:01:01.000-1800"
+ },
+ "running" : {
+ "sync-state" : "NONE_REQUESTED",
+ "last-sync-time" : "2022-01-01T01:01:01.000-1800"
+ }
+ }
+}
\ No newline at end of file